Skip to content

Commit c3860fc

Browse files
authored
Merge branch 'dev' into feat/MIFOSAC-668-Loan-dashboard
2 parents 0470e66 + e7d68c5 commit c3860fc

8 files changed

Lines changed: 160 additions & 110 deletions

File tree

core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/theme/Color.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,14 @@ object AppColors {
257257
val loanActiveStatus = Color(0xFF5CB85C)
258258
val loanClosedObligationsMetStatus = Color(0xFF5CB85C)
259259
val loanPendingStatus = Color(0xFFFFA500)
260-
val loanOverpaidStatus = Color(0xFF800080)
260+
val loanApprovedStatus = Color(0xFFFFA500)
261+
val loanClosedOverpaidStatus = Color(0xFF800080)
262+
val loanClosedObligationsMetStatus = Color(0xFF5CB85C)
263+
val loanClosedRescheduled = Color(0xFF000AAD)
264+
val loanClosedWrittenOffStatus = Color(0xFF990000)
265+
val loanRejectedStatus = Color(0xFF990000)
266+
val loanWithdrawnByApplicantStatus = Color(0xFF990000)
267+
261268
val loanUnknownStatus = Color(0xFF9E9E9E)
262269
val loanRejectedStatus = Color(0xFF990000)
263270
val loanClosedWrittenOffStatus = Color(0xFF990000)

core/ui/src/commonMain/composeResources/drawable/send_money.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
android:tint="?attr/colorControlNormal"
1717
android:autoMirrored="true">
1818
<path
19-
android:fillColor="@android:color/white"
19+
android:fillColor="#FFFFFF"
2020
android:pathData="M240,790Q136,763 68,678Q0,593 0,480Q0,367 68,282Q136,197 240,170L240,254Q169,278 124.5,340Q80,402 80,480Q80,558 124.5,620Q169,682 240,706L240,790ZM560,800Q427,800 333.5,706.5Q240,613 240,480Q240,347 333.5,253.5Q427,160 560,160Q626,160 684,185Q742,210 786,254L730,310Q697,277 653.5,258.5Q610,240 560,240Q460,240 390,310Q320,380 320,480Q320,580 390,650Q460,720 560,720Q610,720 653.5,701.5Q697,683 730,650L786,706Q742,750 684,775Q626,800 560,800ZM800,640L744,584L808,520L520,520L520,440L808,440L744,376L800,320L960,480L800,640Z"/>
2121
</vector>

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientLoanAccounts/ClientLoanAccountsScreen.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import com.mifos.core.ui.components.MifosEmptyCard
7575
import com.mifos.core.ui.components.MifosProgressIndicator
7676
import com.mifos.core.ui.components.MifosSearchBar
7777
import com.mifos.core.ui.util.EventsEffect
78+
import com.mifos.feature.loan.utils.getLoanStatus
7879
import com.mifos.room.entities.accounts.loans.LoanAccountEntity
7980
import org.jetbrains.compose.resources.painterResource
8081
import org.jetbrains.compose.resources.stringResource
@@ -252,7 +253,7 @@ private fun LoanAccountItem(
252253

253254
type = loan.loanType?.value ?: notAvailable,
254255

255-
status = loan.status?.value ?: notAvailable,
256+
status = loan.status?.let { stringResource(it.getLoanStatus().label) } ?: notAvailable,
256257

257258
menuList = buildLoanActions(loan),
258259

feature/loan/src/commonMain/composeResources/values/strings.xml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,6 @@
164164
<string name="feature_loan_profile_item_notes_subtitle">Additional internal comments</string>
165165
<string name="feature_loan_profile_item_standing_instructions_title">Standing Instructions</string>
166166
<string name="feature_loan_profile_item_standing_instructions_subtitle">Automated payment settings</string>
167-
<string name="feature_loan_profile_status_active">Active</string>
168-
<string name="feature_loan_profile_status_pending">Pending</string>
169-
<string name="feature_loan_profile_status_overpaid">Overpaid</string>
170-
<string name="feature_loan_profile_status_unknown">Unknown</string>
171167
<string name="feature_loan_profile_action_approve">Approve Account</string>
172168
<string name="feature_loan_profile_action_repayment">Make Repayment</string>
173169
<string name="feature_loan_profile_action_transfer">Transfer Funds</string>
@@ -563,4 +559,16 @@
563559
<string name="feature_loan_reschedule_fetch_failed">Failed to load reschedule history.</string>
564560
<string name="feature_loan_reschedule_approve_failed">Failed to approve reschedule.</string>
565561
<string name="feature_loan_reschedule_delete_failed">Failed to delete reschedule.</string>
562+
563+
564+
<string name="feature_loan_pending_approval">Pending Approval</string>
565+
<string name="feature_loan_approved">Approved</string>
566+
<string name="feature_loan_withdrawn_by_applicant">Withdrawn by Applicant</string>
567+
<string name="feature_loan_active">Active</string>
568+
<string name="feature_loan_closed_overpaid">Closed (Overpaid)</string>
569+
<string name="feature_loan_closed_obligations_met">Closed (Obligations Met)</string>
570+
<string name="feature_loan_closed_written_off">Closed (Written Off)</string>
571+
<string name="feature_loan_closed_rescheduled">Closed (Rescheduled)</string>
572+
<string name="feature_loan_rejected">Rejected</string>
573+
<string name="feature_loan_unknown">Unknown</string>">
566574
</resources>

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileScreen.kt

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import androidclient.feature.loan.generated.resources.feature_loan_profile_label
1919
import androidclient.feature.loan.generated.resources.feature_loan_profile_label_overpaid_by
2020
import androidclient.feature.loan.generated.resources.feature_loan_profile_section_account_overview
2121
import androidclient.feature.loan.generated.resources.feature_loan_profile_section_actions_details
22-
import androidclient.feature.loan.generated.resources.feature_loan_profile_status_active
2322
import androidx.compose.foundation.background
2423
import androidx.compose.foundation.clickable
2524
import androidx.compose.foundation.layout.Arrangement
@@ -63,6 +62,7 @@ import com.mifos.core.ui.util.EventsEffect
6362
import com.mifos.core.ui.util.TextUtil
6463
import com.mifos.feature.loan.loanAccountProfile.components.LoanAccountProfileActionItem
6564
import com.mifos.feature.loan.loanAccountProfile.components.loanProfileActionItems
65+
import com.mifos.feature.loan.utils.getLoanStatus
6666
import com.mifos.room.entities.accounts.loans.LoanStatusEntity
6767
import com.mifos.room.entities.accounts.loans.LoanWithAssociationsEntity
6868
import com.mifos.room.entities.accounts.loans.LoansAccountSummaryEntity
@@ -110,20 +110,25 @@ internal fun LoanAccountProfileScreen(
110110
}
111111
}
112112
}
113+
113114
is LoanAccountEvent.NavigateToDetail -> {
114115
val loanId = state.loanAccount?.id ?: -1
115116

116117
when (event.detailItem) {
117-
LoanAccountProfileActionItem.RepaymentSchedule -> navigateToRepaymentSchedule(loanId)
118+
LoanAccountProfileActionItem.RepaymentSchedule -> navigateToRepaymentSchedule(
119+
loanId,
120+
)
121+
118122
LoanAccountProfileActionItem.Transactions -> navigateToTransactions(loanId)
119123
LoanAccountProfileActionItem.Charges -> navigateToCharges(loanId)
120124
LoanAccountProfileActionItem.Documents -> navigateToDocuments(loanId)
121125
LoanAccountProfileActionItem.Reschedules -> navigateToReschedules(loanId)
122126
LoanAccountProfileActionItem.Dashboard -> navigateToDashboard(loanId)
123127
LoanAccountProfileActionItem.Notes -> navigateToNotes(loanId)
124-
else -> { }
128+
else -> {}
125129
}
126130
}
131+
127132
LoanAccountEvent.NavigateToAccountDetails -> {}
128133
}
129134
}
@@ -172,7 +177,6 @@ private fun LoanAccountContent(
172177

173178
LoanAccountTopCard(
174179
loanAccount = loanAccount,
175-
statusUi = state.statusUiModel,
176180
onClick = { onAction(LoanAccountAction.OnAccountClick) },
177181
)
178182

@@ -223,15 +227,16 @@ private fun LoanAccountContent(
223227
@Composable
224228
private fun LoanAccountTopCard(
225229
loanAccount: LoanWithAssociationsEntity,
226-
statusUi: LoanStatusUiModel?,
227230
onClick: () -> Unit,
228231
modifier: Modifier = Modifier,
229232
) {
230233
val currencyCode = loanAccount.currency?.code
231234
val decimalPlaces = loanAccount.currency?.decimalPlaces
232235

233-
val balance = CurrencyFormatter.format(loanAccount.summary.totalOutstanding, currencyCode, decimalPlaces)
234-
val arrears = CurrencyFormatter.format(loanAccount.summary.totalOverdue, currencyCode, decimalPlaces)
236+
val balance =
237+
CurrencyFormatter.format(loanAccount.summary.totalOutstanding, currencyCode, decimalPlaces)
238+
val arrears =
239+
CurrencyFormatter.format(loanAccount.summary.totalOverdue, currencyCode, decimalPlaces)
235240
val overpaid = CurrencyFormatter.format(loanAccount.totalOverpaid, currencyCode, decimalPlaces)
236241

237242
MifosCard(
@@ -256,15 +261,18 @@ private fun LoanAccountTopCard(
256261
) {
257262
Column(modifier = Modifier.weight(1f)) {
258263
Text(
259-
text = "${loanAccount.loanProductName?.uppercase().orEmpty()} ${loanAccount.accountNo}".trim(),
264+
text = "${
265+
loanAccount.loanProductName?.uppercase().orEmpty()
266+
} ${loanAccount.accountNo}".trim(),
260267
style = MifosTypography.titleMediumEmphasized,
261268
color = KptTheme.colorScheme.onPrimary,
262269
)
263270

264271
Spacer(Modifier.height(KptTheme.spacing.xs))
265272

266273
Text(
267-
text = loanAccount.clientName ?: stringResource(Res.string.feature_loan_profile_label_client_name_placeholder),
274+
text = loanAccount.clientName
275+
?: stringResource(Res.string.feature_loan_profile_label_client_name_placeholder),
268276
style = MifosTypography.bodyMedium,
269277
color = KptTheme.colorScheme.onPrimary.copy(alpha = 0.8f),
270278
)
@@ -280,21 +288,22 @@ private fun LoanAccountTopCard(
280288

281289
Spacer(Modifier.height(DesignToken.padding.medium))
282290

283-
statusUi?.let { ui ->
284-
Box(
285-
modifier = Modifier
286-
.clip(KptTheme.shapes.large)
287-
.background(ui.color)
288-
.padding(horizontal = DesignToken.padding.medium, vertical = KptTheme.spacing.xs),
289-
contentAlignment = Alignment.Center,
290-
) {
291-
Text(
292-
text = stringResource(ui.labelRes).uppercase(),
293-
color = KptTheme.colorScheme.onPrimary,
294-
style = MifosTypography.labelSmallEmphasized,
295-
fontWeight = FontWeight.Bold,
296-
)
297-
}
291+
Box(
292+
modifier = Modifier
293+
.clip(KptTheme.shapes.large)
294+
.background(loanAccount.status.getLoanStatus().color)
295+
.padding(
296+
horizontal = DesignToken.padding.medium,
297+
vertical = KptTheme.spacing.xs,
298+
),
299+
contentAlignment = Alignment.Center,
300+
) {
301+
Text(
302+
text = stringResource(loanAccount.status.getLoanStatus().label).uppercase(),
303+
color = KptTheme.colorScheme.onPrimary,
304+
style = MifosTypography.labelSmallEmphasized,
305+
fontWeight = FontWeight.Bold,
306+
)
298307
}
299308

300309
Spacer(Modifier.height(KptTheme.spacing.md))
@@ -367,6 +376,7 @@ private fun LoanAccountDialogs(
367376
onRetry = onRetry,
368377
)
369378
}
379+
370380
null -> Unit
371381
}
372382
}
@@ -396,10 +406,6 @@ private class LoanAccountPreviewProvider : PreviewParameterProvider<LoanAccountS
396406
value = "Active",
397407
),
398408
),
399-
statusUiModel = LoanStatusUiModel(
400-
labelRes = Res.string.feature_loan_profile_status_active,
401-
color = AppColors.loanActiveStatus,
402-
),
403409
nextActionButtonRes = Res.string.feature_loan_profile_action_repayment,
404410
dialogState = null,
405411
),

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileViewModel.kt

Lines changed: 13 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,16 @@ import androidclient.feature.loan.generated.resources.feature_loan_profile_actio
1717
import androidclient.feature.loan.generated.resources.feature_loan_profile_error_details_not_found
1818
import androidclient.feature.loan.generated.resources.feature_loan_profile_error_network_not_available
1919
import androidclient.feature.loan.generated.resources.feature_loan_profile_failed_to_load_loan
20-
import androidclient.feature.loan.generated.resources.feature_loan_profile_status_active
21-
import androidclient.feature.loan.generated.resources.feature_loan_profile_status_overpaid
22-
import androidclient.feature.loan.generated.resources.feature_loan_profile_status_pending
23-
import androidclient.feature.loan.generated.resources.feature_loan_profile_status_unknown
24-
import androidx.compose.ui.graphics.Color
2520
import androidx.lifecycle.SavedStateHandle
2621
import androidx.lifecycle.viewModelScope
2722
import androidx.navigation.toRoute
2823
import com.mifos.core.common.utils.DataState
2924
import com.mifos.core.data.repository.LoanAccountSummaryRepository
3025
import com.mifos.core.data.util.NetworkMonitor
31-
import com.mifos.core.designsystem.theme.AppColors
3226
import com.mifos.core.ui.util.BaseViewModel
3327
import com.mifos.feature.loan.loanAccountProfile.components.LoanAccountProfileActionItem
34-
import com.mifos.room.entities.accounts.loans.LoanStatusEntity
28+
import com.mifos.feature.loan.utils.LoanStatus
29+
import com.mifos.feature.loan.utils.getLoanStatus
3530
import com.mifos.room.entities.accounts.loans.LoanWithAssociationsEntity
3631
import kotlinx.coroutines.Job
3732
import kotlinx.coroutines.flow.update
@@ -85,13 +80,12 @@ internal class LoanAccountProfileViewModel(
8580
}
8681
return@collect
8782
}
88-
val currentStatus = loan.status.toProfileStatus()
83+
val currentStatus = loan.status.getLoanStatus()
8984

9085
mutableStateFlow.update {
9186
it.copy(
9287
loanAccount = loan,
9388
dialogState = null,
94-
statusUiModel = calculateStatusUi(currentStatus),
9589
nextActionButtonRes = calculateNextActionResource(currentStatus),
9690
)
9791
}
@@ -111,21 +105,12 @@ internal class LoanAccountProfileViewModel(
111105
}
112106
}
113107

114-
private fun calculateNextActionResource(status: LoanProfileStatus): StringResource {
108+
private fun calculateNextActionResource(status: LoanStatus): StringResource {
115109
return when (status) {
116-
LoanProfileStatus.PENDING -> Res.string.feature_loan_profile_action_approve
117-
LoanProfileStatus.OVERPAID -> Res.string.feature_loan_profile_action_transfer
118-
LoanProfileStatus.ACTIVE -> Res.string.feature_loan_profile_action_repayment
119-
LoanProfileStatus.UNKNOWN -> Res.string.feature_loan_profile_action_view
120-
}
121-
}
122-
123-
private fun calculateStatusUi(status: LoanProfileStatus): LoanStatusUiModel {
124-
return when (status) {
125-
LoanProfileStatus.ACTIVE -> LoanStatusUiModel(Res.string.feature_loan_profile_status_active, AppColors.loanActiveStatus)
126-
LoanProfileStatus.PENDING -> LoanStatusUiModel(Res.string.feature_loan_profile_status_pending, AppColors.loanPendingStatus)
127-
LoanProfileStatus.OVERPAID -> LoanStatusUiModel(Res.string.feature_loan_profile_status_overpaid, AppColors.loanOverpaidStatus)
128-
LoanProfileStatus.UNKNOWN -> LoanStatusUiModel(Res.string.feature_loan_profile_status_unknown, AppColors.loanUnknownStatus)
110+
LoanStatus.PENDING_APPROVAL -> Res.string.feature_loan_profile_action_approve
111+
LoanStatus.CLOSED_OVERPAID -> Res.string.feature_loan_profile_action_transfer
112+
LoanStatus.ACTIVE -> Res.string.feature_loan_profile_action_repayment
113+
else -> Res.string.feature_loan_profile_action_view
129114
}
130115
}
131116

@@ -148,37 +133,19 @@ internal class LoanAccountProfileViewModel(
148133
private fun handleNextAction() {
149134
val account = mutableStateFlow.value.loanAccount ?: return
150135

151-
when (account.status.toProfileStatus()) {
152-
LoanProfileStatus.PENDING -> sendEvent(LoanAccountEvent.NavigateToAction(LoanProfileAction.Approve))
153-
LoanProfileStatus.OVERPAID -> sendEvent(LoanAccountEvent.NavigateToAction(LoanProfileAction.Transfer))
154-
LoanProfileStatus.ACTIVE -> sendEvent(LoanAccountEvent.NavigateToAction(LoanProfileAction.Repayment))
155-
LoanProfileStatus.UNKNOWN -> sendEvent(LoanAccountEvent.NavigateToAccountDetails)
156-
}
157-
}
158-
159-
private fun LoanStatusEntity?.toProfileStatus(): LoanProfileStatus {
160-
if (this == null) return LoanProfileStatus.UNKNOWN
161-
return when {
162-
this.pendingApproval == true -> LoanProfileStatus.PENDING
163-
this.overpaid == true -> LoanProfileStatus.OVERPAID
164-
this.active == true -> LoanProfileStatus.ACTIVE
165-
else -> LoanProfileStatus.UNKNOWN
136+
when (account.status.getLoanStatus()) {
137+
LoanStatus.PENDING_APPROVAL -> sendEvent(LoanAccountEvent.NavigateToAction(LoanProfileAction.Approve))
138+
LoanStatus.CLOSED_OVERPAID -> sendEvent(LoanAccountEvent.NavigateToAction(LoanProfileAction.Transfer))
139+
LoanStatus.ACTIVE -> sendEvent(LoanAccountEvent.NavigateToAction(LoanProfileAction.Repayment))
140+
else -> sendEvent(LoanAccountEvent.NavigateToAccountDetails)
166141
}
167142
}
168143
}
169144

170-
enum class LoanProfileStatus {
171-
ACTIVE,
172-
PENDING,
173-
OVERPAID,
174-
UNKNOWN,
175-
}
176-
177145
data class LoanAccountState(
178146
val loanAccount: LoanWithAssociationsEntity? = null,
179147
val dialogState: DialogState? = null,
180148
val networkConnection: Boolean = false,
181-
val statusUiModel: LoanStatusUiModel? = null,
182149
val nextActionButtonRes: StringResource = Res.string.feature_loan_profile_action_view,
183150
) {
184151
sealed interface DialogState {
@@ -187,11 +154,6 @@ data class LoanAccountState(
187154
}
188155
}
189156

190-
data class LoanStatusUiModel(
191-
val labelRes: StringResource,
192-
val color: Color,
193-
)
194-
195157
sealed interface LoanProfileAction {
196158
data object Approve : LoanProfileAction
197159
data object Repayment : LoanProfileAction

0 commit comments

Comments
 (0)