Skip to content

Commit 377bbfe

Browse files
authored
feat(savingsAccount): preview functionality (#2521)
1 parent efc0851 commit 377bbfe

File tree

15 files changed

+487
-32
lines changed

15 files changed

+487
-32
lines changed

core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/CreateSavingsAccountUseCase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ class CreateSavingsAccountUseCase(
2323
private val repository: SavingsAccountRepository,
2424
) {
2525

26-
operator fun invoke(savingsPayload: SavingsPayload?): Flow<DataState<Savings?>> =
26+
operator fun invoke(savingsPayload: SavingsPayload?): Flow<DataState<Savings>> =
2727
repository.createSavingsAccount(savingsPayload)
2828
}

core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/SavingsPayload.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ class SavingsPayload {
3232
var allowOverdraft: Boolean? = null
3333
var enforceMinRequiredBalance: Boolean? = null
3434
var minRequiredOpeningBalance: String? = null
35+
var minRequiredBalance: String? = null
36+
var lockinPeriodFrequency: Int? = null
37+
var lockinPeriodFrequencyType: Int? = null
38+
39+
var charges: List<ChargesPayload>? = null
3540
var nominalAnnualInterestRateOverdraft: String? = null
3641
var overdraftLimit: String? = null
3742
var minOverdraftForInterestCalculation: String? = null

core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerSavings.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ package com.mifos.core.network.datamanager
1212
import com.mifos.core.datastore.UserPreferencesRepository
1313
import com.mifos.core.model.objects.account.loan.SavingsApproval
1414
import com.mifos.core.model.objects.account.saving.SavingsAccountTransactionResponse
15+
import com.mifos.core.model.objects.error.MifosError
1516
import com.mifos.core.model.objects.organisations.ProductSavings
1617
import com.mifos.core.model.objects.payloads.SavingsPayload
1718
import com.mifos.core.network.BaseApiManager
@@ -22,11 +23,14 @@ import com.mifos.room.entities.client.Savings
2223
import com.mifos.room.entities.templates.savings.SavingProductsTemplate
2324
import com.mifos.room.entities.templates.savings.SavingsAccountTransactionTemplateEntity
2425
import com.mifos.room.helper.SavingsDaoHelper
26+
import io.ktor.client.statement.bodyAsText
27+
import io.ktor.http.isSuccess
2528
import kotlinx.coroutines.ExperimentalCoroutinesApi
2629
import kotlinx.coroutines.flow.Flow
2730
import kotlinx.coroutines.flow.flatMapLatest
2831
import kotlinx.coroutines.flow.flow
2932
import kotlinx.coroutines.flow.map
33+
import kotlinx.serialization.json.Json
3034

3135
/**
3236
* Created by Rajan Maurya on 17/08/16.
@@ -285,7 +289,24 @@ class DataManagerSavings(
285289
get() = mBaseApiManager.savingsService.allSavingsAccounts()
286290

287291
fun createSavingsAccount(savingsPayload: SavingsPayload?): Flow<Savings> {
288-
return mBaseApiManager.savingsService.createSavingsAccount(savingsPayload)
292+
return mBaseApiManager.savingsService.createSavingsAccount(savingsPayload).map { response ->
293+
val responseText = response.bodyAsText()
294+
val json = Json { ignoreUnknownKeys = true }
295+
296+
if (!response.status.isSuccess()) {
297+
val errorMessage = try {
298+
val errorResponse = json.decodeFromString<MifosError>(responseText)
299+
errorResponse.errors.firstOrNull()?.defaultUserMessage
300+
?: errorResponse.defaultUserMessage
301+
?: "HTTP ${response.status.value} ${response.status.description}"
302+
} catch (e: Exception) {
303+
"HTTP ${response.status.value} ${response.status.description}"
304+
}
305+
throw IllegalStateException(errorMessage)
306+
}
307+
308+
json.decodeFromString<Savings>(responseText)
309+
}
289310
}
290311

291312
val getSavingsAccountTemplate: Flow<SavingProductsTemplate>

core/network/src/commonMain/kotlin/com/mifos/core/network/services/SavingsAccountService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ import com.mifos.core.network.GenericResponse
1717
import com.mifos.room.basemodel.APIEndPoint
1818
import com.mifos.room.entities.accounts.savings.SavingsAccountTransactionRequestEntity
1919
import com.mifos.room.entities.accounts.savings.SavingsAccountWithAssociationsEntity
20-
import com.mifos.room.entities.client.Savings
2120
import com.mifos.room.entities.templates.savings.SavingProductsTemplate
2221
import com.mifos.room.entities.templates.savings.SavingsAccountTransactionTemplateEntity
2322
import de.jensklingenberg.ktorfit.http.Body
2423
import de.jensklingenberg.ktorfit.http.GET
2524
import de.jensklingenberg.ktorfit.http.POST
2625
import de.jensklingenberg.ktorfit.http.Path
2726
import de.jensklingenberg.ktorfit.http.Query
27+
import io.ktor.client.statement.HttpResponse
2828
import kotlinx.coroutines.flow.Flow
2929

3030
/**
@@ -106,7 +106,7 @@ interface SavingsAccountService {
106106
fun allSavingsAccounts(): Flow<List<ProductSavings>>
107107

108108
@POST(APIEndPoint.CREATE_SAVINGS_ACCOUNTS)
109-
fun createSavingsAccount(@Body savingsPayload: SavingsPayload?): Flow<Savings>
109+
fun createSavingsAccount(@Body savingsPayload: SavingsPayload?): Flow<HttpResponse>
110110

111111
@GET(APIEndPoint.CREATE_SAVINGS_PRODUCTS + "/template")
112112
fun savingsAccountTemplate(): Flow<SavingProductsTemplate>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
9+
*/
10+
package com.mifos.core.ui.components
11+
12+
import androidx.compose.foundation.border
13+
import androidx.compose.foundation.layout.Box
14+
import androidx.compose.foundation.layout.Column
15+
import androidx.compose.foundation.layout.Row
16+
import androidx.compose.foundation.layout.Spacer
17+
import androidx.compose.foundation.layout.fillMaxWidth
18+
import androidx.compose.foundation.layout.height
19+
import androidx.compose.foundation.layout.padding
20+
import androidx.compose.foundation.shape.RoundedCornerShape
21+
import androidx.compose.material3.MaterialTheme
22+
import androidx.compose.material3.Text
23+
import androidx.compose.runtime.Composable
24+
import androidx.compose.ui.Alignment
25+
import androidx.compose.ui.Modifier
26+
import androidx.compose.ui.unit.Dp
27+
import androidx.compose.ui.unit.dp
28+
import com.mifos.core.designsystem.theme.DesignToken
29+
import com.mifos.core.designsystem.theme.MifosTypography
30+
import org.jetbrains.compose.ui.tooling.preview.Preview
31+
32+
@Composable
33+
fun MifosGeneralCardComponentOutline(
34+
modifier: Modifier = Modifier,
35+
borderCorner: Dp = DesignToken.sizes.iconMiny,
36+
content: @Composable () -> Unit,
37+
) {
38+
Box(
39+
modifier = modifier
40+
.border(
41+
width = 1.dp,
42+
shape = RoundedCornerShape(
43+
topStart = 12.dp,
44+
topEnd = 12.dp,
45+
bottomStart = borderCorner,
46+
bottomEnd = borderCorner,
47+
),
48+
color = MaterialTheme.colorScheme.secondaryContainer,
49+
),
50+
) {
51+
content()
52+
}
53+
}
54+
55+
@Composable
56+
fun MifosGeneralRowItem(
57+
keyContent: @Composable () -> Unit,
58+
valueContent: @Composable () -> Unit,
59+
) {
60+
Row(
61+
modifier = Modifier.fillMaxWidth(),
62+
verticalAlignment = Alignment.CenterVertically,
63+
) {
64+
Box(
65+
modifier = Modifier.weight(1f),
66+
contentAlignment = Alignment.CenterStart,
67+
) { keyContent() }
68+
69+
Box(
70+
modifier = Modifier.weight(1f),
71+
contentAlignment = Alignment.CenterEnd,
72+
) { valueContent() }
73+
}
74+
}
75+
76+
@Composable
77+
fun MifosGeneralCard(
78+
modifier: Modifier = Modifier,
79+
contentMap: Map<String, String>,
80+
separator: String = " : ",
81+
) {
82+
MifosGeneralCardComponentOutline {
83+
Column(
84+
modifier = modifier.padding(DesignToken.padding.large),
85+
) {
86+
contentMap.entries.forEachIndexed { index, map ->
87+
MifosGeneralRowItem(
88+
keyContent = { Text(text = map.key + separator, style = MifosTypography.labelMediumEmphasized) },
89+
valueContent = { Text(text = map.value, style = MifosTypography.labelMediumEmphasized) },
90+
)
91+
if (index < contentMap.size - 1) {
92+
Spacer(modifier = Modifier.height(DesignToken.padding.small))
93+
}
94+
}
95+
}
96+
}
97+
}
98+
99+
@Preview
100+
@Composable
101+
fun MifosPreviewGeneralCard() {
102+
MaterialTheme {
103+
MifosGeneralCard(
104+
contentMap = mapOf(
105+
"title" to "answer",
106+
"title1" to "ans1",
107+
"title2" to "ans2",
108+
"title3" to "ans3",
109+
"title4" to "ans4",
110+
),
111+
)
112+
}
113+
}

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientGeneral/ClientProfileGeneralNavigation.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ package com.mifos.feature.client.clientGeneral
1212
import androidx.navigation.NavController
1313
import androidx.navigation.NavGraphBuilder
1414
import androidx.navigation.compose.composable
15+
import com.mifos.feature.client.clientProfile.ClientProfileRoute
16+
import com.mifos.feature.client.navigation.ClientListScreenRoute
1517
import kotlinx.serialization.Serializable
1618

1719
@Serializable
@@ -51,3 +53,12 @@ fun NavController.navigateToClientProfileGeneralRoute(id: Int) {
5153
ClientProfileGeneralRoute(id = id),
5254
)
5355
}
56+
57+
fun NavController.navigateToClientProfileGeneralRouteOnStatus(id: Int) {
58+
popBackStack(0, true)
59+
navigate(ClientListScreenRoute)
60+
navigate(ClientProfileRoute(id))
61+
navigate(ClientProfileGeneralRoute(id = id)) {
62+
launchSingleTop = true
63+
}
64+
}

feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import com.mifos.feature.client.clientEditProfile.clientEditProfileDestination
4545
import com.mifos.feature.client.clientEditProfile.navigateToClientProfileEditProfileRoute
4646
import com.mifos.feature.client.clientGeneral.clientProfileGeneralDestination
4747
import com.mifos.feature.client.clientGeneral.navigateToClientProfileGeneralRoute
48+
import com.mifos.feature.client.clientGeneral.navigateToClientProfileGeneralRouteOnStatus
4849
import com.mifos.feature.client.clientIdentifiersAddUpdate.clientIdentifiersAddUpdateDestination
4950
import com.mifos.feature.client.clientIdentifiersAddUpdate.onNavigateToClientIdentifiersAddUpdateScreen
5051
import com.mifos.feature.client.clientIdentifiersList.clientIdentifiersListDestination
@@ -339,6 +340,7 @@ fun NavGraphBuilder.clientNavGraph(
339340
onBackPressed = navController::popBackStack,
340341
loadMoreSavingsAccountInfo = navController::navigateToDataTable,
341342
loadDocuments = navController::navigateToDocumentListScreen,
343+
onFinish = navController::navigateToClientProfileGeneralRouteOnStatus,
342344
)
343345

344346
shareAccountDestination()

feature/savings/src/commonMain/composeResources/values/feature_savings_strings.xml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<string name="feature_savings_savingsAccountSummary">Savings Account Summary</string>
1414
<string name="feature_savings_documents">Documents</string>
1515
<string name="feature_savings_client_name">Client Name</string>
16-
<string name="feature_savings_product_name">Product Name</string>
16+
<string name="feature_savings_product_name">Product Name*</string>
1717
<string name="feature_savings_account_balance">Account Balance</string>
1818
<string name="feature_savings_total_deposits">Total Deposits</string>
1919
<string name="feature_savings_total_withdrawals">Total Withdrawals</string>
@@ -28,7 +28,7 @@
2828
<string name="feature_savings_running_balance">Running Balance</string>
2929
<string name="feature_savings_saving_account_id">Saving Account Id</string>
3030
<string name="feature_savings_account_number">Account Number</string>
31-
<string name="feature_savings_currency">Currency</string>
31+
<string name="feature_savings_currency">Currency*</string>
3232
<string name="feature_savings_approve_savings">Approve Savings</string>
3333
<string name="feature_savings_activate_savings">Activate Savings</string>
3434
<string name="feature_savings_savings_account_closed">Savings Account Closed</string>
@@ -67,7 +67,7 @@
6767
<string name="feature_savings_back">Back</string>
6868
<string name="feature_savings_create_savings_account">Add Savings Account</string>
6969
<string name="feature_savings_savings_account_submitted_for_approval">The Savings Account has been submitted forApproval</string>
70-
<string name="feature_savings_field_officer">Field Officer</string>
70+
<string name="feature_savings_field_officer">Field Officer*</string>
7171
<string name="feature_savings_external_id">External ID</string>
7272
<string name="feature_savings_submitted_on">Submitted On</string>
7373
<string name="feature_savings_nominal">Nominal annual interest </string>
@@ -139,6 +139,17 @@
139139
<string name="step_charges_active">Active</string>
140140
<string name="step_charges_edit_charge">Edit Charge</string>
141141

142+
<string name="feature_savings_yes">Yes</string>
143+
<string name="feature_savings_no">No</string>
144+
<string name="feature_savings_continue">Continue</string>
145+
<string name="feature_savings_success">Success</string>
146+
<string name="feature_savings_failed">Failed</string>
147+
148+
<string name="feature_savings_new_savings_account_submitted_success">New Savings Account Application Submitted Successfully</string>
149+
<string name="feature_savings_new_savings_account_submitted_failed">Failed to apply for new savings account with the provided details</string>
150+
151+
<string name="feature_savings_charges_active_count">%1$d active charges</string>
152+
142153
</resources>
143154

144155

feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/navigation/SavingsNavigation.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import kotlinx.serialization.Serializable
2828
fun NavGraphBuilder.savingsDestination(
2929
navController: NavController,
3030
onBackPressed: () -> Unit,
31+
onFinish: (id: Int) -> Unit,
3132
loadMoreSavingsAccountInfo: (String, Int) -> Unit,
3233
loadDocuments: (Int, String) -> Unit,
3334
) {
@@ -85,7 +86,7 @@ fun NavGraphBuilder.savingsDestination(
8586
savingsAccountDestination(
8687
navController = navController,
8788
onNavigateBack = onBackPressed,
88-
onFinish = onBackPressed,
89+
onFinish = onFinish,
8990
)
9091
}
9192

feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccount/SavingAccountViewModel.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.mifos.core.domain.useCases.GetGroupSavingsAccountTemplateByProductUse
2222
import com.mifos.core.domain.useCases.LoadSavingsAccountsAndTemplateUseCase
2323
import com.mifos.core.model.objects.payloads.SavingsPayload
2424
import com.mifos.feature.savings.navigation.SavingsAccountRoute
25+
import com.mifos.room.entities.client.Savings
2526
import com.mifos.room.entities.templates.savings.SavingProductsTemplate
2627
import kotlinx.coroutines.flow.MutableStateFlow
2728
import kotlinx.coroutines.flow.StateFlow
@@ -128,11 +129,13 @@ class SavingAccountViewModel(
128129
_savingAccountUiState.value =
129130
SavingAccountUiState.ShowProgress
130131

131-
is DataState.Success ->
132+
is DataState.Success -> {
132133
_savingAccountUiState.value =
133134
SavingAccountUiState.ShowSavingsAccountCreatedSuccessfully(
134-
dataState.data,
135+
Savings(),
136+
// dataState.data,
135137
)
138+
}
136139
}
137140
}
138141
}

0 commit comments

Comments
 (0)