diff --git a/core/database/src/commonMain/kotlin/com/mifos/room/entities/templates/recurringDeposit/RecurringDepositAccountTemplate.kt b/core/database/src/commonMain/kotlin/com/mifos/room/entities/templates/recurringDeposit/RecurringDepositAccountTemplate.kt index 73a353edae7..7c8b4e6f393 100644 --- a/core/database/src/commonMain/kotlin/com/mifos/room/entities/templates/recurringDeposit/RecurringDepositAccountTemplate.kt +++ b/core/database/src/commonMain/kotlin/com/mifos/room/entities/templates/recurringDeposit/RecurringDepositAccountTemplate.kt @@ -44,7 +44,6 @@ data class RecurringDepositAccountTemplate( val adjustAdvanceTowardsFuturePayments: Boolean? = null, val allowWithdrawal: Boolean? = null, @IgnoredOnParcel val chargeOptions: List? = null, -// val charges: List? = null, val clientId: Int? = null, val clientName: String? = null, @IgnoredOnParcel val currency: Currency? = null, diff --git a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt index 92201a86aa0..c6f362a4ca8 100644 --- a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt +++ b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt @@ -13,7 +13,7 @@ import kotlinx.serialization.Serializable @Serializable data class RecurringDepositAccountPayload( - // val charges: List? = null, + val charges: List? = null, val adjustAdvanceTowardsFuturePayments: Boolean? = null, val allowWithdrawal: Boolean? = null, val clientId: Int? = null, @@ -39,3 +39,9 @@ data class RecurringDepositAccountPayload( val recurringFrequencyType: Int? = null, val submittedOnDate: String? = null, ) + +@Serializable +data class ChargeItem( + val chargeId: Int? = null, + val amount: Double? = null, +) diff --git a/feature/client/src/commonMain/composeResources/values/strings.xml b/feature/client/src/commonMain/composeResources/values/strings.xml index c707d04d55f..13df11794e1 100644 --- a/feature/client/src/commonMain/composeResources/values/strings.xml +++ b/feature/client/src/commonMain/composeResources/values/strings.xml @@ -583,6 +583,7 @@ Edit Charge Add Add + Click on Add New to Add Charge diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt index 39618d8bfd2..d5bb35597fd 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt @@ -14,6 +14,7 @@ import androidclient.feature.client.generated.resources.feature_share_account_ba import androidclient.feature.client.generated.resources.feature_share_account_charge_add import androidclient.feature.client.generated.resources.feature_share_account_charge_add_new_charge import androidclient.feature.client.generated.resources.feature_share_account_charge_btn_add_new +import androidclient.feature.client.generated.resources.feature_share_account_charge_click_on_add_new import androidclient.feature.client.generated.resources.feature_share_account_charge_edit_charge import androidclient.feature.client.generated.resources.feature_share_account_charge_view_charges import androidclient.feature.client.generated.resources.feature_share_account_charges @@ -48,6 +49,7 @@ import com.mifos.core.ui.components.Actions import com.mifos.core.ui.components.AddChargeBottomSheet import com.mifos.core.ui.components.MifosActionsChargeListingComponent import com.mifos.core.ui.components.MifosBreadcrumbNavBar +import com.mifos.core.ui.components.MifosEmptyCard import com.mifos.core.ui.components.MifosProgressIndicator import com.mifos.core.ui.components.MifosProgressIndicatorOverlay import com.mifos.core.ui.components.MifosStepper @@ -118,6 +120,7 @@ fun CreateShareAccountDialog( onAction = onAction, ) } + is CreateShareAccountState.DialogState.SuccessResponseStatus -> { LaunchedEffect(state.launchEffectKey) { snackbarHostState.showSnackbar( @@ -132,6 +135,7 @@ fun CreateShareAccountDialog( } } } + null -> Unit } } @@ -287,35 +291,42 @@ private fun ShowChargesDialog( text = stringResource(Res.string.feature_share_account_charge_view_charges), style = MifosTypography.titleMediumEmphasized, ) - state.addedCharges.forEachIndexed { index, charge -> - val chargesValue = state.chargeOptions - .firstOrNull { it.id == charge.chargeId } - MifosActionsChargeListingComponent( - chargeTitle = chargesValue?.name ?: "", - type = chargesValue?.chargeCalculationType?.value ?: "", - collectedOn = chargesValue?.chargeTimeType?.value ?: "", - amount = charge.amount.toString(), - onActionClicked = { action -> - when (action) { - is Actions.Delete -> { - onAction( - CreateShareAccountAction.DeleteChargeFromSelectedCharges( - index, - ), - ) - } + if (state.addedCharges.isNotEmpty()) { + state.addedCharges.forEachIndexed { index, charge -> + val chargesValue = state.chargeOptions + .firstOrNull { it.id == charge.chargeId } + MifosActionsChargeListingComponent( + chargeTitle = chargesValue?.name ?: "", + type = chargesValue?.chargeCalculationType?.value ?: "", + collectedOn = chargesValue?.chargeTimeType?.value ?: "", + amount = charge.amount.toString(), + onActionClicked = { action -> + when (action) { + is Actions.Delete -> { + expandedIndex = -1 + onAction( + CreateShareAccountAction.DeleteChargeFromSelectedCharges( + index, + ), + ) + } - is Actions.Edit -> { - onAction(CreateShareAccountAction.EditChargeDialog(index)) - } + is Actions.Edit -> { + onAction(CreateShareAccountAction.EditChargeDialog(index)) + } - else -> {} - } - }, - isExpanded = expandedIndex == index, - onExpandToggle = { - expandedIndex = if (expandedIndex == index) -1 else index - }, + else -> {} + } + }, + isExpanded = expandedIndex == index, + onExpandToggle = { + expandedIndex = if (expandedIndex == index) -1 else index + }, + ) + } + } else { + MifosEmptyCard( + msg = stringResource(Res.string.feature_share_account_charge_click_on_add_new), ) } } diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/ChargesPage.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/ChargesPage.kt index eb7943a22d7..a8a9d0e7134 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/ChargesPage.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/ChargesPage.kt @@ -49,7 +49,7 @@ fun ChargesPage( modifier: Modifier = Modifier, onAction: (CreateShareAccountAction) -> Unit, ) { - Column(modifier = Modifier.fillMaxSize()) { + Column(modifier = Modifier.fillMaxSize().padding(bottom = DesignToken.padding.large)) { Column( modifier = modifier.weight(1f).verticalScroll(rememberScrollState()), ) { diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/TermsPage.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/TermsPage.kt index 56f15e93744..0bb0be4286b 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/TermsPage.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/TermsPage.kt @@ -138,7 +138,7 @@ fun TermsPage( onValueChange = { onAction(CreateShareAccountAction.OnTotalSharesChange(it)) }, - label = stringResource(Res.string.feature_share_account_terms_total_shares), + label = stringResource(Res.string.feature_share_account_terms_total_shares) + "*", config = MifosTextFieldConfig( keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number, @@ -162,7 +162,7 @@ fun TermsPage( options = state.savingsAccountOptions.map { it.accountNo + (it.savingsProductName?.let { name -> " - $name" }.orEmpty()) }, - label = stringResource(Res.string.feature_share_account_terms_default_savings_account), + label = stringResource(Res.string.feature_share_account_terms_default_savings_account) + "*", errorMessage = state.savingsAccountError?.let { stringResource(it) }, ) diff --git a/feature/loan/src/commonMain/composeResources/values/strings.xml b/feature/loan/src/commonMain/composeResources/values/strings.xml index ecb30e82080..fc89bc7e7f8 100644 --- a/feature/loan/src/commonMain/composeResources/values/strings.xml +++ b/feature/loan/src/commonMain/composeResources/values/strings.xml @@ -221,6 +221,8 @@ Amount Type Collected On + Click on Add New to Add Charge + Repayment Schedule 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 28e7cdafaac..da6e9bffc3f 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 @@ -15,6 +15,7 @@ import androidclient.feature.loan.generated.resources.add_new import androidclient.feature.loan.generated.resources.add_new_charge import androidclient.feature.loan.generated.resources.add_new_collateral import androidclient.feature.loan.generated.resources.back +import androidclient.feature.loan.generated.resources.click_on_add_new import androidclient.feature.loan.generated.resources.collateral import androidclient.feature.loan.generated.resources.edit_charge import androidclient.feature.loan.generated.resources.feature_loan_cancel @@ -63,6 +64,7 @@ import com.mifos.core.ui.components.Actions import com.mifos.core.ui.components.AddChargeBottomSheet import com.mifos.core.ui.components.MifosActionsChargeListingComponent import com.mifos.core.ui.components.MifosBreadcrumbNavBar +import com.mifos.core.ui.components.MifosEmptyCard import com.mifos.core.ui.components.MifosListingComponentOutline import com.mifos.core.ui.components.MifosListingRowItem import com.mifos.core.ui.components.MifosProgressIndicator @@ -393,7 +395,7 @@ private fun AddNewChargeDialog( } else { stringResource(Res.string.add) }, - dismissText = stringResource(Res.string.feature_loan_cancel), + dismissText = stringResource(Res.string.back), showDatePicker = state.showChargesDatePick, selectedChargeName = if (state.chooseChargeIndex == -1) { "" @@ -481,34 +483,41 @@ private fun ShowChargesDialog( ) } } else { - state.addedCharges.forEachIndexed { index, it -> - MifosActionsChargeListingComponent( - chargeTitle = it.name.toString(), - type = it.type.toString(), - date = it.date, - collectedOn = it.collectedOn, - amount = it.amount.toString(), - onActionClicked = { action -> - when (action) { - is Actions.Delete -> { - onAction( - NewLoanAccountAction.DeleteChargeFromSelectedCharges( - index, - ), - ) - } + if (state.addedCharges.isNotEmpty()) { + state.addedCharges.forEachIndexed { index, it -> + MifosActionsChargeListingComponent( + chargeTitle = it.name.toString(), + type = it.type.toString(), + date = it.date, + collectedOn = it.collectedOn, + amount = it.amount.toString(), + onActionClicked = { action -> + when (action) { + is Actions.Delete -> { + expandedIndex = -1 + onAction( + NewLoanAccountAction.DeleteChargeFromSelectedCharges( + index, + ), + ) + } - is Actions.Edit -> { - onAction(NewLoanAccountAction.EditChargeDialog(index)) - } + is Actions.Edit -> { + onAction(NewLoanAccountAction.EditChargeDialog(index)) + } - else -> {} - } - }, - isExpanded = expandedIndex == index, - onExpandToggle = { - expandedIndex = if (expandedIndex == index) -1 else index - }, + else -> {} + } + }, + isExpanded = expandedIndex == index, + onExpandToggle = { + expandedIndex = if (expandedIndex == index) -1 else index + }, + ) + } + } else { + MifosEmptyCard( + msg = stringResource(Res.string.click_on_add_new), ) } } diff --git a/feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml b/feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml index 59f9f29e2f8..d1bc8665ee0 100644 --- a/feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml +++ b/feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml @@ -62,4 +62,13 @@ Yes No Empty Date + Add New Charge + Active Charge + Add New + Amount + Collected On + Add + Edit Charge + View Charges + Click on Add New to Add Charge \ No newline at end of file diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt index cbfbb523b96..9e55509be03 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt @@ -32,11 +32,13 @@ import com.mifos.core.ui.components.MifosStepper import com.mifos.core.ui.components.Step import com.mifos.core.ui.util.EventsEffect import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.RecurringAccountAction.NavigateToStep +import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.AddNewChargeDialog import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.ChargesPage import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.DetailsPage import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.InterestPage import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.RateChart import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.SettingPage +import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.ShowChargesDialog import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.TermsPage import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @@ -83,6 +85,21 @@ fun RecurringAccountDialog( onAction = onAction, ) } + is RecurringAccountState.DialogState.AddNewCharge -> { + AddNewChargeDialog( + state = state, + isEdit = state.dialogState.edit, + onAction = onAction, + index = state.dialogState.index, + ) + } + + RecurringAccountState.DialogState.ShowCharges -> { + ShowChargesDialog( + state = state, + onAction = onAction, + ) + } null -> Unit } } @@ -121,7 +138,8 @@ private fun RecurringAccountScaffold( }, Step(name = stringResource(Res.string.feature_recurring_deposit_step_charges)) { ChargesPage( - onNext = { onAction(RecurringAccountAction.OnNextPress) }, + state = state, + onAction = onAction, ) }, ) diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt index 186432a2123..3124e893771 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt @@ -18,6 +18,7 @@ import com.mifos.core.common.utils.DataState import com.mifos.core.common.utils.DateHelper import com.mifos.core.data.repository.RecurringAccountRepository import com.mifos.core.data.util.NetworkMonitor +import com.mifos.core.model.objects.payloads.ChargeItem import com.mifos.core.model.objects.payloads.RecurringDepositAccountPayload import com.mifos.core.model.objects.template.recurring.FieldOfficerOption import com.mifos.core.ui.util.BaseViewModel @@ -94,6 +95,7 @@ class RecurringAccountViewModel( val recurringFreq = settings.minimumDepositTerm.frequency.toIntOrNull() val payload = RecurringDepositAccountPayload( + charges = state.addedCharges, adjustAdvanceTowardsFuturePayments = settings.adjustAdvancePayments, allowWithdrawal = settings.allowWithdrawals, clientId = state.clientId, @@ -700,6 +702,92 @@ class RecurringAccountViewModel( ) } } + + is RecurringAccountAction.DeleteChargeFromSelectedCharges -> { + val newCharges = state.addedCharges.toMutableList().apply { + removeAt(action.index) + } + mutableStateFlow.update { + it.copy(addedCharges = newCharges) + } + } + is RecurringAccountAction.EditCharge -> { + val createdData = ChargeItem( + chargeId = state.template.chargeOptions?.get(action.index)?.id, + amount = state.chargeAmount.toDoubleOrNull(), + ) + + val currentAddedCharges = state.addedCharges.toMutableList() + currentAddedCharges[action.index] = createdData + mutableStateFlow.update { + it.copy( + addedCharges = currentAddedCharges, + chooseChargeIndex = null, + dialogState = RecurringAccountState.DialogState.ShowCharges, + chargeAmount = "", + ) + } + } + is RecurringAccountAction.EditChargeDialog -> { + val selectedEditCharge = state.addedCharges[action.index] + val chooseChargeIndex = state.template.chargeOptions + ?.indexOfFirst { it.id == selectedEditCharge.chargeId } + + mutableStateFlow.update { + it.copy( + chargeAmount = selectedEditCharge.amount.toString(), + chooseChargeIndex = chooseChargeIndex, + dialogState = RecurringAccountState.DialogState.AddNewCharge( + true, + action.index, + ), + ) + } + } + is RecurringAccountAction.OnChargeAmountChange -> { + mutableStateFlow.update { + it.copy( + chargeAmount = action.amount, + ) + } + } + is RecurringAccountAction.OnChooseChargeIndexChange -> { + mutableStateFlow.update { + it.copy( + chooseChargeIndex = action.index, + ) + } + } + RecurringAccountAction.ShowAddChargeDialog -> { + mutableStateFlow.update { + it.copy( + dialogState = RecurringAccountState.DialogState.AddNewCharge(false), + ) + } + } + RecurringAccountAction.ShowListOfChargesDialog -> { + mutableStateFlow.update { + it.copy( + dialogState = RecurringAccountState.DialogState.ShowCharges, + ) + } + } + + RecurringAccountAction.AddChargeToList -> { + val createdData = ChargeItem( + chargeId = state.template.chargeOptions?.get(state.chooseChargeIndex!!)?.id, + amount = state.chargeAmount.toDoubleOrNull(), + ) + + mutableStateFlow.update { + it.copy( + addedCharges = it.addedCharges + createdData, + chooseChargeIndex = null, + dialogState = null, + chargeAmount = "", + ) + } + } } } } @@ -718,6 +806,9 @@ data class RecurringAccountState( val currencyError: String? = null, val isOverlayLoading: Boolean = false, val dialogState: DialogState? = null, + val addedCharges: List = emptyList(), + val chargeAmount: String = "", + val chooseChargeIndex: Int? = null, ) { sealed interface ScreenState { data class Error(val message: String) : ScreenState @@ -726,6 +817,8 @@ data class RecurringAccountState( } sealed interface DialogState { data object RateChartDialog : DialogState + data class AddNewCharge(val edit: Boolean, val index: Int = -1) : DialogState + data object ShowCharges : DialogState } val isRateChartEmpty = !template.accountChart?.chartSlabs.isNullOrEmpty() @@ -821,6 +914,14 @@ sealed class RecurringAccountAction { data object Retry : RecurringAccountAction() object OnShowRateChartDialog : RecurringAccountAction() object OnDismissDialog : RecurringAccountAction() + object ShowAddChargeDialog : RecurringAccountAction() + object ShowListOfChargesDialog : RecurringAccountAction() + data class EditCharge(val index: Int) : RecurringAccountAction() + data class OnChooseChargeIndexChange(val index: Int) : RecurringAccountAction() + data class OnChargeAmountChange(val amount: String) : RecurringAccountAction() + data class DeleteChargeFromSelectedCharges(val index: Int) : RecurringAccountAction() + data class EditChargeDialog(val index: Int) : RecurringAccountAction() + data object AddChargeToList : RecurringAccountAction() sealed class RecurringAccountDetailsAction : RecurringAccountAction() { data class OnProductNameChange(val index: Int) : RecurringAccountDetailsAction() diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt index cacdd0e1248..92e56e6d588 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt @@ -10,26 +10,249 @@ package com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages import androidclient.feature.recurringdeposit.generated.resources.Res -import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_charges_page -import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_next_button +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_active_charge +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_add_new_charge +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_back +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_btn_add +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_btn_add_new +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_click_on_add_new +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_edit_charge +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_next +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_step_charges +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_view +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_view_charge +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.material3.Button +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp +import com.mifos.core.designsystem.component.MifosBottomSheet +import com.mifos.core.designsystem.icon.MifosIcons +import com.mifos.core.designsystem.theme.DesignToken +import com.mifos.core.designsystem.theme.MifosTypography +import com.mifos.core.ui.components.Actions +import com.mifos.core.ui.components.AddChargeBottomSheet +import com.mifos.core.ui.components.MifosActionsChargeListingComponent +import com.mifos.core.ui.components.MifosEmptyCard +import com.mifos.core.ui.components.MifosRowWithTextAndButton +import com.mifos.core.ui.components.MifosTwoButtonRow +import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.RecurringAccountAction +import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.RecurringAccountState import org.jetbrains.compose.resources.stringResource @Composable -fun ChargesPage(onNext: () -> Unit) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text(stringResource(Res.string.feature_recurring_deposit_charges_page)) - Spacer(Modifier.height(8.dp)) - Button(onClick = onNext) { - Text(stringResource(Res.string.feature_recurring_deposit_next_button)) +fun ChargesPage( + state: RecurringAccountState, + onAction: (RecurringAccountAction) -> Unit, +) { + Column(modifier = Modifier.fillMaxSize().padding(bottom = DesignToken.padding.large)) { + Column( + modifier = Modifier.weight(1f).verticalScroll(rememberScrollState()), + ) { + Text( + stringResource(Res.string.feature_recurring_deposit_step_charges), + style = MifosTypography.labelLargeEmphasized, + ) + Spacer(Modifier.height(DesignToken.padding.large)) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.End, + ) { + Row( + modifier = Modifier.clickable { + onAction( + RecurringAccountAction.ShowAddChargeDialog, + ) + }, + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = MifosIcons.Add, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(DesignToken.sizes.iconSmall), + ) + + Text( + text = stringResource(Res.string.feature_recurring_deposit_btn_add_new), + color = MaterialTheme.colorScheme.primary, + style = MifosTypography.labelLargeEmphasized, + ) + } + } + + Spacer(Modifier.height(DesignToken.padding.large)) + + MifosRowWithTextAndButton( + onBtnClick = { + onAction( + RecurringAccountAction.ShowListOfChargesDialog, + ) + }, + btnText = stringResource(Res.string.feature_recurring_deposit_view), + text = state.addedCharges.size.toString() + " " + stringResource(Res.string.feature_recurring_deposit_active_charge), + btnEnabled = state.addedCharges.isNotEmpty(), + ) } + MifosTwoButtonRow( + firstBtnText = stringResource(Res.string.feature_recurring_deposit_back), + secondBtnText = stringResource(Res.string.feature_recurring_deposit_next), + onFirstBtnClick = { + onAction(RecurringAccountAction.OnBackPress) + }, + onSecondBtnClick = { + onAction(RecurringAccountAction.OnNextPress) + }, + ) } } + +@Composable +internal fun AddNewChargeDialog( + isEdit: Boolean, + index: Int = -1, + state: RecurringAccountState, + onAction: (RecurringAccountAction) -> Unit, +) { + AddChargeBottomSheet( + title = if (isEdit) { + stringResource(Res.string.feature_recurring_deposit_edit_charge) + } else { + stringResource(Res.string.feature_recurring_deposit_add_new_charge) + }, + confirmText = if (isEdit) { + stringResource(Res.string.feature_recurring_deposit_edit_charge) + } else { + stringResource(Res.string.feature_recurring_deposit_btn_add) + }, + dismissText = stringResource(Res.string.feature_recurring_deposit_back), + selectedChargeName = if (state.chooseChargeIndex == null) { + "" + } else { + state.template.chargeOptions?.get(state.chooseChargeIndex)?.name ?: "" + }, + chargeAmount = state.chargeAmount, + chargeType = if (state.chooseChargeIndex == null) { + "" + } else { + state.template.chargeOptions?.get(state.chooseChargeIndex)?.chargeCalculationType?.value + ?: "" + }, + chargeCollectedOn = if (state.chooseChargeIndex == null) { + "" + } else { + state.template.chargeOptions?.get(state.chooseChargeIndex)?.chargeTimeType?.value + ?: "" + }, + chargeOptions = state.template.chargeOptions?.map { it.name ?: "" } ?: emptyList(), + onConfirm = { + if (isEdit) { + onAction(RecurringAccountAction.EditCharge(index)) + } else { + onAction(RecurringAccountAction.AddChargeToList) + } + }, + onDismiss = { onAction(RecurringAccountAction.OnDismissDialog) }, + onChargeSelected = { index, _ -> + onAction(RecurringAccountAction.OnChooseChargeIndexChange(index)) + }, + onDatePick = {}, + onDateChange = {}, + onAmountChange = { amount -> + onAction(RecurringAccountAction.OnChargeAmountChange(amount)) + }, + ) +} + +@Composable +internal fun ShowChargesDialog( + state: RecurringAccountState, + onAction: (RecurringAccountAction) -> Unit, +) { + var expandedIndex: Int? by rememberSaveable { mutableStateOf(-1) } + + MifosBottomSheet( + onDismiss = { + onAction(RecurringAccountAction.OnDismissDialog) + }, + content = { + Column( + modifier = Modifier.fillMaxWidth().padding(DesignToken.padding.large), + verticalArrangement = Arrangement.spacedBy(DesignToken.padding.largeIncreased), + ) { + Text( + text = stringResource(Res.string.feature_recurring_deposit_view_charge), + style = MifosTypography.titleMediumEmphasized, + ) + + if (state.addedCharges.isNotEmpty()) { + state.addedCharges.forEachIndexed { index, charge -> + val chargesValue = state.template.chargeOptions + ?.firstOrNull { it.id == charge.chargeId } + MifosActionsChargeListingComponent( + chargeTitle = chargesValue?.name ?: "", + type = chargesValue?.chargeCalculationType?.value ?: "", + collectedOn = chargesValue?.chargeTimeType?.value ?: "", + amount = charge.amount.toString(), + onActionClicked = { action -> + when (action) { + is Actions.Delete -> { + expandedIndex = -1 + onAction( + RecurringAccountAction.DeleteChargeFromSelectedCharges( + index, + ), + ) + } + + is Actions.Edit -> { + onAction(RecurringAccountAction.EditChargeDialog(index)) + } + + else -> {} + } + }, + isExpanded = expandedIndex == index, + onExpandToggle = { + expandedIndex = if (expandedIndex == index) -1 else index + }, + ) + } + } else { + MifosEmptyCard( + msg = stringResource(Res.string.feature_recurring_deposit_click_on_add_new), + ) + } + + MifosTwoButtonRow( + firstBtnText = stringResource(Res.string.feature_recurring_deposit_back), + secondBtnText = stringResource(Res.string.feature_recurring_deposit_btn_add_new), + onFirstBtnClick = { + onAction(RecurringAccountAction.OnDismissDialog) + }, + onSecondBtnClick = { + onAction(RecurringAccountAction.ShowAddChargeDialog) + }, + ) + } + }, + ) +} diff --git a/feature/savings/src/commonMain/composeResources/values/feature_savings_strings.xml b/feature/savings/src/commonMain/composeResources/values/feature_savings_strings.xml index b140ea57bad..9f2768ba703 100644 --- a/feature/savings/src/commonMain/composeResources/values/feature_savings_strings.xml +++ b/feature/savings/src/commonMain/composeResources/values/feature_savings_strings.xml @@ -146,6 +146,8 @@ Failed Savings Account Created Successfully %1$d active charges + Click on Add New to Add Charge + This field cannot be empty diff --git a/feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt b/feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt index 967919994ac..ee02523ff7e 100644 --- a/feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt +++ b/feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt @@ -11,7 +11,7 @@ package com.mifos.feature.savings.savingsAccountv2 import androidclient.feature.savings.generated.resources.Res import androidclient.feature.savings.generated.resources.feature_savings_back -import androidclient.feature.savings.generated.resources.feature_savings_cancel +import androidclient.feature.savings.generated.resources.feature_savings_charges_click_on_add_new import androidclient.feature.savings.generated.resources.feature_savings_create_savings_account import androidclient.feature.savings.generated.resources.step_charges import androidclient.feature.savings.generated.resources.step_charges_add @@ -26,8 +26,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text @@ -52,6 +50,7 @@ import com.mifos.core.ui.components.Actions import com.mifos.core.ui.components.AddChargeBottomSheet import com.mifos.core.ui.components.MifosActionsChargeListingComponent import com.mifos.core.ui.components.MifosBreadcrumbNavBar +import com.mifos.core.ui.components.MifosEmptyCard import com.mifos.core.ui.components.MifosProgressIndicator import com.mifos.core.ui.components.MifosProgressIndicatorOverlay import com.mifos.core.ui.components.MifosStepper @@ -245,7 +244,7 @@ private fun AddNewChargeDialog( } else { stringResource(Res.string.step_charges_add) }, - dismissText = stringResource(Res.string.feature_savings_cancel), + dismissText = stringResource(Res.string.feature_savings_back), showDatePicker = state.showChargesDatePick, selectedChargeName = if (state.chooseChargeIndex == -1) { "" @@ -313,60 +312,64 @@ private fun ShowChargesDialog( onAction(SavingsAccountAction.DismissDialog) }, content = { - LazyColumn( + Column( modifier = Modifier.fillMaxWidth().padding(DesignToken.padding.large), verticalArrangement = Arrangement.spacedBy(DesignToken.padding.largeIncreased), ) { - item { - Text( - text = stringResource(Res.string.step_charges_view) + " " + stringResource( - Res.string.step_charges, - ), - style = MifosTypography.titleMediumEmphasized, - ) - } - itemsIndexed(items = state.addedCharges) { index, it -> - MifosActionsChargeListingComponent( - chargeTitle = it.name.toString(), - type = it.type.toString(), - date = it.date, - collectedOn = it.collectedOn, - amount = it.amount.toString(), - onActionClicked = { action -> - when (action) { - is Actions.Delete -> { - onAction( - SavingsAccountAction.DeleteChargeFromSelectedCharges( - index, - ), - ) - } + Text( + text = stringResource(Res.string.step_charges_view) + " " + stringResource( + Res.string.step_charges, + ), + style = MifosTypography.titleMediumEmphasized, + ) - is Actions.Edit -> { - onAction(SavingsAccountAction.EditChargeDialog(index)) - } + if (state.addedCharges.isNotEmpty()) { + state.addedCharges.forEachIndexed { index, it -> + MifosActionsChargeListingComponent( + chargeTitle = it.name.toString(), + type = it.type.toString(), + date = it.date, + collectedOn = it.collectedOn, + amount = it.amount.toString(), + onActionClicked = { action -> + when (action) { + is Actions.Delete -> { + expandedIndex = -1 + onAction( + SavingsAccountAction.DeleteChargeFromSelectedCharges( + index, + ), + ) + } - else -> {} - } - }, - isExpanded = expandedIndex == it.id, - onExpandToggle = { - expandedIndex = if (expandedIndex == it.id) -1 else it.id - }, - ) - } - item { - MifosTwoButtonRow( - firstBtnText = stringResource(Res.string.feature_savings_back), - secondBtnText = stringResource(Res.string.step_charges_add_new), - onFirstBtnClick = { - onAction(SavingsAccountAction.DismissDialog) - }, - onSecondBtnClick = { - onAction(SavingsAccountAction.ShowAddChargeDialog) - }, + is Actions.Edit -> { + onAction(SavingsAccountAction.EditChargeDialog(index)) + } + + else -> {} + } + }, + isExpanded = expandedIndex == it.id, + onExpandToggle = { + expandedIndex = if (expandedIndex == it.id) -1 else it.id + }, + ) + } + } else { + MifosEmptyCard( + msg = stringResource(Res.string.feature_savings_charges_click_on_add_new), ) } + MifosTwoButtonRow( + firstBtnText = stringResource(Res.string.feature_savings_back), + secondBtnText = stringResource(Res.string.step_charges_add_new), + onFirstBtnClick = { + onAction(SavingsAccountAction.DismissDialog) + }, + onSecondBtnClick = { + onAction(SavingsAccountAction.ShowAddChargeDialog) + }, + ) } }, ) diff --git a/feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt b/feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt index 0fce0c0765e..67be26f8730 100644 --- a/feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt +++ b/feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt @@ -104,7 +104,6 @@ fun ChargesPage( onSecondBtnClick = { onAction(SavingsAccountAction.NextStep) }, - modifier = Modifier.padding(top = DesignToken.padding.small), ) } }