From e95d9fe726c7e6da70d9d44cef0c2b616af8d3ae Mon Sep 17 00:00:00 2001 From: Khushi Chourase Date: Mon, 6 Oct 2025 22:36:00 +0530 Subject: [PATCH 1/2] =?UTF-8?q?MIFOSAC-555=20New=20Fixed=20Deposits=20Acco?= =?UTF-8?q?unt=20=E2=80=93=20Preview=20Step?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FixedDepositAccountFlowScreen.kt | 91 ++++ .../FixedDepositAccountRoute.kt | 24 + .../preview/PreviewStepRoute.kt | 28 + .../preview/PreviewStepScreen.kt | 506 ++++++++++++++++++ .../preview/PreviewStepViewModel.kt | 229 ++++++++ .../client/navigation/ClientNavigation.kt | 12 + 6 files changed, 890 insertions(+) create mode 100644 feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountFlowScreen.kt create mode 100644 feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepRoute.kt create mode 100644 feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepScreen.kt create mode 100644 feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepViewModel.kt diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountFlowScreen.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountFlowScreen.kt new file mode 100644 index 0000000000..8feb85d337 --- /dev/null +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountFlowScreen.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package com.mifos.feature.client.fixedDepositAccount + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.rememberNavController +import androidx.compose.ui.Modifier + +// Import all your step destinations +import com.mifos.feature.client.fixedDepositAccount.details.DetailsStepRoute +import com.mifos.feature.client.fixedDepositAccount.details.detailsStepDestination +import com.mifos.feature.client.fixedDepositAccount.details.navigateToDetailsStep +import com.mifos.feature.client.fixedDepositAccount.currency.currencyStepDestination +import com.mifos.feature.client.fixedDepositAccount.currency.navigateToCurrencyStep +import com.mifos.feature.client.fixedDepositAccount.terms.termsStepDestination +import com.mifos.feature.client.fixedDepositAccount.terms.navigateToTermsStep +import com.mifos.feature.client.fixedDepositAccount.settings.settingsStepDestination +import com.mifos.feature.client.fixedDepositAccount.settings.navigateToSettingsStep +import com.mifos.feature.client.fixedDepositAccount.charges.chargesStepDestination +import com.mifos.feature.client.fixedDepositAccount.charges.navigateToChargesStep +import com.mifos.feature.client.fixedDepositAccount.preview.previewStepDestination +import com.mifos.feature.client.fixedDepositAccount.preview.navigateToPreviewStep + +@Composable +fun FixedDepositAccountFlowScreen( + clientId: Int, + navigateBack: () -> Unit, + onAccountCreated: (accountId: String) -> Unit, + modifier: Modifier = Modifier +) { + val navController = rememberNavController() + + NavHost( + navController = navController, + startDestination = DetailsStepRoute(clientId), + modifier = modifier + ) { + // Step 1: Details + detailsStepDestination( + navController = navController, + navigateBack = navigateBack, + onNext = { navController.navigateToCurrencyStep(clientId) } + ) + + // Step 2: Currency 👈 ADD HERE + currencyStepDestination( + navController = navController, + navigateBack = { navController.popBackStack() }, + onNext = { navController.navigateToTermsStep(clientId) } + ) + + // Step 3: Terms + termsStepDestination( + navController = navController, + navigateBack = { navController.popBackStack() }, + onNext = { navController.navigateToSettingsStep(clientId) } + ) + + // Step 4: Settings + settingsStepDestination( + navController = navController, + navigateBack = { navController.popBackStack() }, + onNext = { navController.navigateToChargesStep(clientId) } + ) + + // Step 5: Charges + chargesStepDestination( + navController = navController, + navigateBack = { navController.popBackStack() }, + onNext = { navController.navigateToPreviewStep(clientId) } + ) + + // Step 6: Preview + previewStepDestination( + navController = navController, + navigateBack = { navController.popBackStack() }, + onSubmit = { + // Account created successfully + onAccountCreated("accountId") + } + ) + } +} \ No newline at end of file diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountRoute.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountRoute.kt index 9ab632d95e..19c5761fa1 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountRoute.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountRoute.kt @@ -31,9 +31,33 @@ fun NavGraphBuilder.clientFixedDepositAccountDestination( navigateBack = navigateBack, onApproveAccount = onApproveAccount, onViewAccount = onViewAccount, + onCreateNew = { clientId -> + // Navigate to the multi-step flow + navController.navigateToFixedDepositFlow(clientId) ) } } +// Add the multi-step flow route + composable { backStackEntry -> + val route = backStackEntry.toRoute() + FixedDepositAccountFlowScreen( + clientId = route.clientId, + navigateBack = { navController.popBackStack() }, + onAccountCreated = { accountId -> + // Navigate back to listing or details + navController.popBackStack() + } + ) + } +} +@Serializable +data class FixedDepositAccountFlowRoute( + val clientId: Int +) + +fun NavController.navigateToFixedDepositFlow(clientId: Int) { + this.navigate(FixedDepositAccountFlowRoute(clientId = clientId)) +} fun NavController.navigateToFixedDepositAccountRoute( clientId: Int, diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepRoute.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepRoute.kt new file mode 100644 index 0000000000..2f583e6590 --- /dev/null +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepRoute.kt @@ -0,0 +1,28 @@ +package com.mifos.feature.client.fixedDepositAccount.preview + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import kotlinx.serialization.Serializable + +@Serializable +data class PreviewStepRoute( + val clientId: Int = -1 +) + +fun NavGraphBuilder.previewStepDestination( + navController: NavController, + navigateBack: () -> Unit, + onSubmit: () -> Unit +) { + composable { + PreviewStepScreenContainer( + navigateBack = navigateBack, + onSubmit = onSubmit + ) + } +} + +fun NavController.navigateToPreviewStep(clientId: Int) { + this.navigate(PreviewStepRoute(clientId = clientId)) +} \ No newline at end of file diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepScreen.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepScreen.kt new file mode 100644 index 0000000000..6d3b173f09 --- /dev/null +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepScreen.kt @@ -0,0 +1,506 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/android-client/blob/master/LICENSE.md + */ + +package com.mifos.feature.client.fixedDepositAccount.preview + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.mifos.core.designsystem.component.MifosButton +import com.mifos.core.designsystem.component.MifosOutlinedButton +import com.mifos.core.designsystem.icon.MifosIcons +import com.mifos.core.designsystem.theme.DesignToken +import com.mifos.core.designsystem.theme.MifosTypography + +@Composable +fun PreviewStepScreen( + state: PreviewStepState, + onAction: (PreviewStepAction) -> Unit, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .fillMaxSize() + .padding(DesignToken.padding.large) + ) { + // Step Title + Text( + text = "Preview", + style = MifosTypography.headlineMedium, + modifier = Modifier.padding(bottom = DesignToken.padding.medium) + ) + + Text( + text = "Review all entered details before submission", + style = MifosTypography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(bottom = DesignToken.padding.large) + ) + + // Scrollable Content + LazyColumn( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(DesignToken.spacing.medium) + ) { + // Details Section + item { + PreviewSection( + title = "Details", + isExpanded = state.expandedSections.contains("details"), + onToggle = { onAction(PreviewStepAction.ToggleSection("details")) } + ) { + PreviewField("Product Name", state.productName) + PreviewField("Submission Date", state.submissionDate) + PreviewField("External ID", state.externalId) + PreviewField("Field Officer", state.fieldOfficer) + } + } + + // Currency Section + item { + PreviewSection( + title = "Currency", + isExpanded = state.expandedSections.contains("currency"), + onToggle = { onAction(PreviewStepAction.ToggleSection("currency")) } + ) { + PreviewField("Currency", state.currency) + PreviewField("Currency Multiple", state.currencyMultiple) + PreviewField("Decimal Places", state.decimalPlaces) + } + } + + // Terms Section + item { + PreviewSection( + title = "Terms", + isExpanded = state.expandedSections.contains("terms"), + onToggle = { onAction(PreviewStepAction.ToggleSection("terms")) } + ) { + PreviewField("Fixed Deposit Amount", state.depositAmount) + PreviewField("Deposit Period", state.depositPeriod) + PreviewField("Interest Compounding Period", state.compoundingPeriod) + PreviewField("Interest Posting Period", state.postingPeriod) + PreviewField("Interest Calculation Method", state.calculationMethod) + PreviewField("Days in Year", state.daysInYear) + } + } + + // Settings Section + item { + PreviewSection( + title = "Settings", + isExpanded = state.expandedSections.contains("settings"), + onToggle = { onAction(PreviewStepAction.ToggleSection("settings")) } + ) { + PreviewField("Lock-in Period", state.lockInPeriod) + PreviewField("Minimum Deposit Term", state.minDepositTerm) + PreviewField("Transfer Interest to Savings", state.transferToSavings) + PreviewField("Maturity Instructions", state.maturityInstructions) + PreviewField("Apply Penal Interest", state.applyPenalInterest) + } + } + + // Interest Rate Chart Section + item { + PreviewSection( + title = "Interest Rate Chart", + isExpanded = state.expandedSections.contains("interest_chart"), + onToggle = { onAction(PreviewStepAction.ToggleSection("interest_chart")) } + ) { + PreviewField("Name", state.chartName) + PreviewField("Valid From", state.chartValidFrom) + PreviewField("Valid To", state.chartValidTo) + PreviewField("Description", state.chartDescription) + PreviewField("Grouping by Amount", state.chartGroupingByAmount) + + Spacer(modifier = Modifier.height(DesignToken.spacing.small)) + + // Rate Chart Table + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = "Rate Chart Details", + style = MifosTypography.labelLarge, + fontWeight = FontWeight.Bold + ) + Row( + horizontalArrangement = Arrangement.spacedBy(DesignToken.spacing.small) + ) { + TextButton( + onClick = { onAction(PreviewStepAction.ViewRateChart) } + ) { + Icon( + imageVector = MifosIcons.Visibility, + contentDescription = "View" + ) + Spacer(modifier = Modifier.width(4.dp)) + Text("View") + } + TextButton( + onClick = { onAction(PreviewStepAction.DownloadRateChart) } + ) { + Icon( + imageVector = MifosIcons.Download, + contentDescription = "Download" + ) + Spacer(modifier = Modifier.width(4.dp)) + Text("Download") + } + } + } + } + } + } + + // Navigation Buttons + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = DesignToken.padding.large), + horizontalArrangement = Arrangement.spacedBy(DesignToken.spacing.medium) + ) { + MifosOutlinedButton( + onClick = { onAction(PreviewStepAction.NavigateBack) }, + modifier = Modifier.weight(1f) + ) { + Text("Back") + } + + MifosButton( + onClick = { onAction(PreviewStepAction.Submit) }, + modifier = Modifier.weight(1f) + ) { + Text("Submit") + } + } + } + + // Rate Chart Modal + if (state.showRateChartModal) { + InterestRateChartModal( + rateChartEntries = state.rateChartEntries, + onDismiss = { onAction(PreviewStepAction.DismissRateChartModal) }, + onEdit = { entry -> onAction(PreviewStepAction.EditRateChartEntry(entry)) }, + onDelete = { entry -> onAction(PreviewStepAction.DeleteRateChartEntry(entry)) }, + onDownload = { onAction(PreviewStepAction.DownloadRateChart) } + ) + } + + // Delete Confirmation Dialog + if (state.showDeleteConfirmation != null) { + AlertDialog( + onDismissRequest = { onAction(PreviewStepAction.DismissDeleteConfirmation) }, + title = { Text("Confirm Delete") }, + text = { Text("Are you sure you want to delete this rate chart entry?") }, + confirmButton = { + TextButton( + onClick = { onAction(PreviewStepAction.ConfirmDelete) } + ) { + Text("Delete") + } + }, + dismissButton = { + TextButton( + onClick = { onAction(PreviewStepAction.DismissDeleteConfirmation) } + ) { + Text("Cancel") + } + } + ) + } +} + +@Composable +private fun PreviewSection( + title: String, + isExpanded: Boolean, + onToggle: () -> Unit, + modifier: Modifier = Modifier, + content: @Composable ColumnScope.() -> Unit +) { + Card( + modifier = modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceVariant + ) + ) { + Column(modifier = Modifier.padding(DesignToken.padding.medium)) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { onToggle() }, + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = title, + style = MifosTypography.titleMedium, + fontWeight = FontWeight.Bold + ) + Icon( + imageVector = if (isExpanded) MifosIcons.ExpandLess else MifosIcons.ExpandMore, + contentDescription = if (isExpanded) "Collapse" else "Expand" + ) + } + + if (isExpanded) { + Spacer(modifier = Modifier.height(DesignToken.spacing.medium)) + Divider() + Spacer(modifier = Modifier.height(DesignToken.spacing.medium)) + content() + } + } + } +} + +@Composable +private fun PreviewField( + label: String, + value: String, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier + .fillMaxWidth() + .padding(vertical = DesignToken.spacing.extraSmall), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = label, + style = MifosTypography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.weight(1f) + ) + Text( + text = value.ifEmpty { "-" }, + style = MifosTypography.bodyMedium, + fontWeight = FontWeight.Medium, + modifier = Modifier.weight(1f), + textAlign = androidx.compose.ui.text.style.TextAlign.End + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun InterestRateChartModal( + rateChartEntries: List, + onDismiss: () -> Unit, + onEdit: (RateChartEntry) -> Unit, + onDelete: (RateChartEntry) -> Unit, + onDownload: () -> Unit +) { + AlertDialog( + onDismissRequest = onDismiss, + modifier = Modifier.fillMaxWidth(0.95f) + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + shape = MaterialTheme.shapes.large, + tonalElevation = 6.dp + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(DesignToken.padding.large) + ) { + Text( + text = "Interest Rate Chart", + style = MifosTypography.headlineSmall, + modifier = Modifier.padding(bottom = DesignToken.padding.medium) + ) + + LazyColumn( + modifier = Modifier.weight(1f, fill = false), + verticalArrangement = Arrangement.spacedBy(DesignToken.spacing.small) + ) { + items(rateChartEntries) { entry -> + RateChartEntryCard( + entry = entry, + onEdit = { onEdit(entry) }, + onDelete = { onDelete(entry) } + ) + } + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = DesignToken.padding.medium), + horizontalArrangement = Arrangement.spacedBy(DesignToken.spacing.small) + ) { + MifosOutlinedButton( + onClick = onDismiss, + modifier = Modifier.weight(1f) + ) { + Text("Back") + } + MifosButton( + onClick = onDownload, + modifier = Modifier.weight(1f) + ) { + Icon( + imageVector = MifosIcons.Download, + contentDescription = null + ) + Spacer(modifier = Modifier.width(4.dp)) + Text("Download") + } + } + } + } + } +} + +@Composable +private fun RateChartEntryCard( + entry: RateChartEntry, + onEdit: () -> Unit, + onDelete: () -> Unit, + modifier: Modifier = Modifier +) { + Card( + modifier = modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surface + ) + ) { + Column( + modifier = Modifier.padding(DesignToken.padding.medium) + ) { + PreviewField("Amount Range", entry.amountRange) + PreviewField("Period", entry.period) + PreviewField("Interest Rate", "${entry.interestRate}%") + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = DesignToken.spacing.small), + horizontalArrangement = Arrangement.End + ) { + TextButton(onClick = onEdit) { + Icon( + imageVector = MifosIcons.Edit, + contentDescription = "Edit" + ) + Spacer(modifier = Modifier.width(4.dp)) + Text("Edit") + } + TextButton(onClick = onDelete) { + Icon( + imageVector = MifosIcons.Delete, + contentDescription = "Delete" + ) + Spacer(modifier = Modifier.width(4.dp)) + Text("Delete") + } + } + } + } +} +@Composable +fun PreviewStepScreenContainer( + navigateBack: () -> Unit, + onSubmit: () -> Unit, + viewModel: PreviewStepViewModel = koinViewModel() +) { + val state by viewModel.stateFlow.collectAsStateWithLifecycle() + + EventsEffect(viewModel.eventFlow) { event -> + when (event) { + is PreviewStepEvent.NavigateToChargesStep -> navigateBack() + is PreviewStepEvent.NavigateToConfirmation -> onSubmit() + is PreviewStepEvent.ShowMessage -> { + // Show snackbar or toast + } + is PreviewStepEvent.ShowError -> { + // Show error dialog + } + is PreviewStepEvent.NavigateToEditRateChart -> { + // Handle edit navigation + } + } + } + + PreviewStepScreen( + state = state, + onAction = remember(viewModel) { { viewModel.trySendAction(it) } } + ) +} + +// Data Models +data class PreviewStepState( + // Details + val productName: String = "", + val submissionDate: String = "", + val externalId: String = "", + val fieldOfficer: String = "", + + // Currency + val currency: String = "", + val currencyMultiple: String = "", + val decimalPlaces: String = "", + + // Terms + val depositAmount: String = "", + val depositPeriod: String = "", + val compoundingPeriod: String = "", + val postingPeriod: String = "", + val calculationMethod: String = "", + val daysInYear: String = "", + + // Settings + val lockInPeriod: String = "", + val minDepositTerm: String = "", + val transferToSavings: String = "", + val maturityInstructions: String = "", + val applyPenalInterest: String = "", + + // Interest Rate Chart + val chartName: String = "", + val chartValidFrom: String = "", + val chartValidTo: String = "", + val chartDescription: String = "", + val chartGroupingByAmount: String = "", + val rateChartEntries: List = emptyList(), + + // UI State + val expandedSections: Set = setOf("details", "currency", "terms", "settings", "interest_chart"), + val showRateChartModal: Boolean = false, + val showDeleteConfirmation: RateChartEntry? = null +) + +data class RateChartEntry( + val id: String, + val amountRange: String, + val period: String, + val interestRate: Double +) + +sealed class PreviewStepAction { + data class ToggleSection(val sectionId: String) : PreviewStepAction() + data object ViewRateChart : PreviewStepAction() + data object DownloadRateChart : PreviewStepAction() + data object DismissRateChartModal : PreviewStepAction() + data class EditRateChartEntry(val entry: RateChartEntry) : PreviewStepAction() + data class DeleteRateChartEntry(val entry: RateChartEntry) : PreviewStepAction() + data object ConfirmDelete : PreviewStepAction() + data object DismissDeleteConfirmation : PreviewStepAction() + data object NavigateBack : PreviewStepAction() + data object Submit : PreviewStepAction() +} \ No newline at end of file diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepViewModel.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepViewModel.kt new file mode 100644 index 0000000000..2668f5545b --- /dev/null +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/preview/PreviewStepViewModel.kt @@ -0,0 +1,229 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/android-client/blob/master/LICENSE.md + */ + +package com.mifos.feature.client.fixedDepositAccount.preview + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import com.mifos.core.ui.util.BaseViewModel +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +class PreviewStepViewModel( + private val savedStateHandle: SavedStateHandle +) : BaseViewModel< + PreviewStepState, + PreviewStepEvent, + PreviewStepAction +>(initialState = PreviewStepState()) { + + init { + loadPreviewData() + } + + override fun handleAction(action: PreviewStepAction) { + when (action) { + is PreviewStepAction.ToggleSection -> toggleSection(action.sectionId) + PreviewStepAction.ViewRateChart -> showRateChartModal() + PreviewStepAction.DownloadRateChart -> downloadRateChart() + PreviewStepAction.DismissRateChartModal -> dismissRateChartModal() + is PreviewStepAction.EditRateChartEntry -> editRateChartEntry(action.entry) + is PreviewStepAction.DeleteRateChartEntry -> showDeleteConfirmation(action.entry) + PreviewStepAction.ConfirmDelete -> confirmDelete() + PreviewStepAction.DismissDeleteConfirmation -> dismissDeleteConfirmation() + PreviewStepAction.NavigateBack -> navigateBack() + PreviewStepAction.Submit -> submitAccount() + } + } + + private fun loadPreviewData() { + viewModelScope.launch { + // Load data from SavedStateHandle or repository + // This should retrieve data from previous steps + + // Example: Loading from SavedStateHandle + val productName = savedStateHandle.get("productName") ?: "" + val submissionDate = savedStateHandle.get("submissionDate") ?: "" + val externalId = savedStateHandle.get("externalId") ?: "" + val fieldOfficer = savedStateHandle.get("fieldOfficer") ?: "" + + val currency = savedStateHandle.get("currency") ?: "" + val currencyMultiple = savedStateHandle.get("currencyMultiple") ?: "" + val decimalPlaces = savedStateHandle.get("decimalPlaces") ?: "" + + val depositAmount = savedStateHandle.get("depositAmount") ?: "" + val depositPeriod = savedStateHandle.get("depositPeriod") ?: "" + val compoundingPeriod = savedStateHandle.get("compoundingPeriod") ?: "" + val postingPeriod = savedStateHandle.get("postingPeriod") ?: "" + val calculationMethod = savedStateHandle.get("calculationMethod") ?: "" + val daysInYear = savedStateHandle.get("daysInYear") ?: "" + + val lockInPeriod = savedStateHandle.get("lockInPeriod") ?: "" + val minDepositTerm = savedStateHandle.get("minDepositTerm") ?: "" + val transferToSavings = savedStateHandle.get("transferToSavings") ?: "" + val maturityInstructions = savedStateHandle.get("maturityInstructions") ?: "" + val applyPenalInterest = savedStateHandle.get("applyPenalInterest") ?: "" + + val chartName = savedStateHandle.get("chartName") ?: "" + val chartValidFrom = savedStateHandle.get("chartValidFrom") ?: "" + val chartValidTo = savedStateHandle.get("chartValidTo") ?: "" + val chartDescription = savedStateHandle.get("chartDescription") ?: "" + val chartGroupingByAmount = savedStateHandle.get("chartGroupingByAmount") ?: "" + + // Load rate chart entries + // This would typically come from a repository or saved state + val rateChartEntries = listOf( + RateChartEntry( + id = "1", + amountRange = "0 - 10,000", + period = "3-6 months", + interestRate = 5.5 + ), + RateChartEntry( + id = "2", + amountRange = "10,000 - 50,000", + period = "6-12 months", + interestRate = 6.0 + ), + RateChartEntry( + id = "3", + amountRange = "50,000+", + period = "12+ months", + interestRate = 6.5 + ) + ) + + mutableStateFlow.update { + it.copy( + productName = productName, + submissionDate = submissionDate, + externalId = externalId, + fieldOfficer = fieldOfficer, + currency = currency, + currencyMultiple = currencyMultiple, + decimalPlaces = decimalPlaces, + depositAmount = depositAmount, + depositPeriod = depositPeriod, + compoundingPeriod = compoundingPeriod, + postingPeriod = postingPeriod, + calculationMethod = calculationMethod, + daysInYear = daysInYear, + lockInPeriod = lockInPeriod, + minDepositTerm = minDepositTerm, + transferToSavings = transferToSavings, + maturityInstructions = maturityInstructions, + applyPenalInterest = applyPenalInterest, + chartName = chartName, + chartValidFrom = chartValidFrom, + chartValidTo = chartValidTo, + chartDescription = chartDescription, + chartGroupingByAmount = chartGroupingByAmount, + rateChartEntries = rateChartEntries + ) + } + } + } + + private fun toggleSection(sectionId: String) { + mutableStateFlow.update { currentState -> + val expandedSections = currentState.expandedSections.toMutableSet() + if (expandedSections.contains(sectionId)) { + expandedSections.remove(sectionId) + } else { + expandedSections.add(sectionId) + } + currentState.copy(expandedSections = expandedSections) + } + } + + private fun showRateChartModal() { + mutableStateFlow.update { + it.copy(showRateChartModal = true) + } + } + + private fun dismissRateChartModal() { + mutableStateFlow.update { + it.copy(showRateChartModal = false) + } + } + + private fun downloadRateChart() { + viewModelScope.launch { + // Implement download logic + // Generate CSV or PDF of the rate chart + sendEvent(PreviewStepEvent.ShowMessage("Rate chart downloaded successfully")) + } + } + + private fun editRateChartEntry(entry: RateChartEntry) { + // Navigate to edit screen or show edit dialog + sendEvent(PreviewStepEvent.NavigateToEditRateChart(entry)) + } + + private fun showDeleteConfirmation(entry: RateChartEntry) { + mutableStateFlow.update { + it.copy(showDeleteConfirmation = entry) + } + } + + private fun dismissDeleteConfirmation() { + mutableStateFlow.update { + it.copy(showDeleteConfirmation = null) + } + } + + private fun confirmDelete() { + val entryToDelete = state.showDeleteConfirmation + if (entryToDelete != null) { + mutableStateFlow.update { currentState -> + currentState.copy( + rateChartEntries = currentState.rateChartEntries.filter { it.id != entryToDelete.id }, + showDeleteConfirmation = null + ) + } + sendEvent(PreviewStepEvent.ShowMessage("Rate chart entry deleted")) + } + } + + private fun navigateBack() { + // Navigate to Charges step (Step 5) + sendEvent(PreviewStepEvent.NavigateToChargesStep) + } + + private fun submitAccount() { + viewModelScope.launch { + // Validate all data before submission + if (validateData()) { + sendEvent(PreviewStepEvent.NavigateToConfirmation) + } else { + sendEvent(PreviewStepEvent.ShowError("Please ensure all required fields are filled")) + } + } + } + + private fun validateData(): Boolean { + // Validate that all required fields are present + with(state) { + return productName.isNotEmpty() && + currency.isNotEmpty() && + depositAmount.isNotEmpty() && + depositPeriod.isNotEmpty() + } + } +} + +sealed class PreviewStepEvent { + data class ShowMessage(val message: String) : PreviewStepEvent() + data class ShowError(val message: String) : PreviewStepEvent() + data class NavigateToEditRateChart(val entry: RateChartEntry) : PreviewStepEvent() + data object NavigateToChargesStep : PreviewStepEvent() + data object NavigateToConfirmation : PreviewStepEvent() +} \ No newline at end of file diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt index c792a8f41d..3b56f66649 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt @@ -483,6 +483,18 @@ fun NavController.navigateCreateClientScreen() { navigate(ClientScreens.CreateClientScreen.route) } +// Add to your NavHost +composable { + FixedDepositAccountFlow( + navController = navController, + // ... other params + ) +} + +// Inside FixedDepositAccountFlow +NavHost( + navController = localNav + @Serializable data object ClientListScreenRoute From 46d907f987385d6be44a91e92561bfefffa469b5 Mon Sep 17 00:00:00 2001 From: Khushi Chourase Date: Thu, 9 Oct 2025 20:26:03 +0530 Subject: [PATCH 2/2] Update FixedDepositAccountFlowScreen.kt --- .../FixedDepositAccountFlowScreen.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountFlowScreen.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountFlowScreen.kt index 8feb85d337..53723fd0e7 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountFlowScreen.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/fixedDepositAccount/FixedDepositAccountFlowScreen.kt @@ -14,7 +14,6 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController import androidx.compose.ui.Modifier -// Import all your step destinations import com.mifos.feature.client.fixedDepositAccount.details.DetailsStepRoute import com.mifos.feature.client.fixedDepositAccount.details.detailsStepDestination import com.mifos.feature.client.fixedDepositAccount.details.navigateToDetailsStep @@ -43,49 +42,50 @@ fun FixedDepositAccountFlowScreen( startDestination = DetailsStepRoute(clientId), modifier = modifier ) { - // Step 1: Details + detailsStepDestination( navController = navController, navigateBack = navigateBack, onNext = { navController.navigateToCurrencyStep(clientId) } ) - // Step 2: Currency 👈 ADD HERE + currencyStepDestination( navController = navController, navigateBack = { navController.popBackStack() }, onNext = { navController.navigateToTermsStep(clientId) } ) - // Step 3: Terms + termsStepDestination( navController = navController, navigateBack = { navController.popBackStack() }, onNext = { navController.navigateToSettingsStep(clientId) } ) - // Step 4: Settings + settingsStepDestination( navController = navController, navigateBack = { navController.popBackStack() }, onNext = { navController.navigateToChargesStep(clientId) } ) - // Step 5: Charges + chargesStepDestination( navController = navController, navigateBack = { navController.popBackStack() }, onNext = { navController.navigateToPreviewStep(clientId) } ) - // Step 6: Preview + previewStepDestination( navController = navController, navigateBack = { navController.popBackStack() }, onSubmit = { - // Account created successfully + onAccountCreated("accountId") } ) } -} \ No newline at end of file + +}