Skip to content

Conversation

@Arinyadav1
Copy link
Contributor

@Arinyadav1 Arinyadav1 commented Dec 9, 2025

Fixes - Jira-#559

Screenshot 2025-12-09 224954 Screenshot 2025-12-09 225005

Summary by CodeRabbit

  • New Features

    • Enhanced fixed deposit account creation with expanded settings including lock-in period configuration, maturity instructions, and penal interest options.
    • Network connectivity monitoring to improve offline user experience.
  • Bug Fixes

    • Enhanced form validation with improved error messaging for deposit amounts, periods, and product selection.
  • Chores

    • Updated UI spacing and layout consistency across account creation flows.
    • Added localization strings for new fixed deposit settings labels.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 9, 2025

Walkthrough

This PR extends the Fixed Deposit and Recurring Deposit account creation flows with enhanced state management, new form fields, and network-aware validation. Changes include expanding the FixedDepositTemplate data model, refactoring CreateFixedDepositAccountViewmodel to use comprehensive state-driven actions with network monitoring, revamping multiple Composable pages to bind to expanded state, adding localization strings, and applying consistent spacing adjustments across multiple feature modules.

Changes

Cohort / File(s) Summary
Data Models & Repository
core/model/src/commonMain/kotlin/com/mifos/core/model/objects/template/recurring/MaturityInstructionOption.kt, core/network/src/commonMain/kotlin/com/mifos/core/network/model/FixedDepositTemplate.kt, core/data/src/commonMain/kotlin/com/mifos/core/data/repository/FixedDepositRepository.kt
Adds MaturityInstructionOption data class; expands FixedDepositTemplate with lockinPeriodFrequencyTypeOptions and maturityInstructionOptions properties; makes productId optional in getFixedDepositTemplate() with default value null.
Fixed Deposit Localization
feature/client/src/commonMain/composeResources/values/strings.xml
Adds 14 new string resources for Fixed Deposit Settings UI labels (lock-in period, frequency, type, deposit terms, maturity instructions, penal interest, etc.).
Fixed Deposit Account ViewModel
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt
Introduces NetworkMonitor dependency with network-aware template loading; expands NewFixedDepositAccountState with lock-in period, multiples, maturity instruction, penal interest, and period fields; adds comprehensive validation and error handling for deposit fields; refactors action dispatch with new OnDetailNext, OnTermNext, PreviousStep, and field-change actions; replaces direct template updates with async error-aware flows.
Fixed Deposit Account Pages
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountScreen.kt, pages/DetailsPage.kt, pages/TermsPage.kt, pages/SettingsPage.kt
Refactors screen scaffold to pass state throughout; converts pages to state-driven with action dispatch; adds header, two-column layout, and expanded form fields; replaces direct callback-based navigation with state-based actions (OnDetailNext, OnTermNext, PreviousStep); adds MifosProgressIndicatorOverlay for loading state; reworks SettingsPage from trivial callback to comprehensive multi-field form with frequency, type, multiples, maturity instruction, and penal interest controls.
Recurring Deposit ViewModel & Pages
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt, pages/DetailsPage.kt, pages/ChargesPage.kt, pages/InterestPage.kt
Removes fieldOfficerError from details state; adds conditional template loading when fieldOfficerOptions is null; introduces ShowCharges dialog state and charge-editing actions (EditCharge, OnChargeAmountChange, OnChooseChargeIndexChange, ShowAddChargeDialog, ShowListOfChargesDialog, AddChargeToList); removes error binding from field officer dropdown in DetailsPage.
UI Spacing Adjustments — Loan Feature
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/ChargesPage.kt, PreviewPage.kt, SchedulePage.kt, TermsPage.kt
Adds vertical spacers with large padding after charges/collateral sections; removes top padding from MifosTwoButtonRow for consistent spacing.
UI Spacing Adjustments — Savings Feature
feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt, DetailsPage.kt, PreviewPage.kt, TermsPage.kt
Adds spacers after charges row; removes top padding from button rows for uniform spacing.
UI Spacing Adjustments — Share Account Feature
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/ChargesPage.kt, DetailsPage.kt, PreviewPage.kt, TermsPage.kt
Adjusts vertical spacing: adds spacer after charges, removes top padding from button rows; adds small spacer before lock-in period section in TermsPage.
Recurring Deposit Spacing
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt
Adds spacer after charges view row.

Sequence Diagram

sequenceDiagram
    participant User
    participant CreateFixedDepositAccountScreen
    participant CreateFixedDepositAccountViewmodel
    participant NetworkMonitor
    participant FixedDepositRepository
    
    User->>CreateFixedDepositAccountScreen: Open Form
    CreateFixedDepositAccountScreen->>CreateFixedDepositAccountViewmodel: init()
    CreateFixedDepositAccountViewmodel->>NetworkMonitor: Check Network
    alt Network Online
        CreateFixedDepositAccountViewmodel->>FixedDepositRepository: loadFixedDepositTemplate()
        FixedDepositRepository-->>CreateFixedDepositAccountViewmodel: Template Data (Success)
        CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: Update State
    else Network Offline
        CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: Show Network Error
    end
    
    rect rgb(220, 240, 255)
    Note over User,FixedDepositRepository: Details Page
    User->>CreateFixedDepositAccountScreen: Select Product & Proceed
    CreateFixedDepositAccountScreen->>CreateFixedDepositAccountViewmodel: OnDetailNext
    CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: Validate Product
    alt Validation Pass
        CreateFixedDepositAccountViewmodel->>NetworkMonitor: Check Network
        CreateFixedDepositAccountViewmodel->>FixedDepositRepository: loadRecurringAccountTemplateWithProduct()
        CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: moveToNextStep()
    else Validation Fail
        CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: Set productError
    end
    end
    
    rect rgb(240, 255, 240)
    Note over User,FixedDepositRepository: Terms Page
    User->>CreateFixedDepositAccountScreen: Enter Deposit Terms & Proceed
    CreateFixedDepositAccountScreen->>CreateFixedDepositAccountViewmodel: OnTermNext
    CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: Validate Terms (Amount, Period, Type)
    alt Validation Pass
        CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: moveToNextStep()
    else Validation Fail
        CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: Set Error Fields
    end
    end
    
    rect rgb(255, 245, 230)
    Note over User,CreateFixedDepositAccountViewmodel: Settings Page
    User->>CreateFixedDepositAccountScreen: Configure Lock-in, Multiples, Maturity, Penal Interest
    CreateFixedDepositAccountScreen->>CreateFixedDepositAccountViewmodel: OnLockInPeriodChange / OnMaturityInstructionChange / etc.
    CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: Update State Fields
    end
    
    User->>CreateFixedDepositAccountScreen: Submit
    CreateFixedDepositAccountViewmodel->>CreateFixedDepositAccountViewmodel: Show isOverlayLoading
    CreateFixedDepositAccountScreen->>CreateFixedDepositAccountScreen: Render MifosProgressIndicatorOverlay
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • CreateFixedDepositAccountViewmodel.kt: Network-aware template loading logic, comprehensive state mutations, new validation flows, and error handling across multiple action handlers—requires careful review of state transitions and async flow handling.
  • SettingsPage.kt: Transformation from trivial callback to full-featured state-driven form with multiple frequency/type dropdowns, multiples, maturity instructions, and conditional penal interest UI; verify action dispatch correctness and state binding completeness.
  • DetailsPage.kt (FixedDeposit): Product selection flow, error handling via productError, conditional rendering based on fieldOfficerOptions, and template loading trigger; ensure state synchronization is correct.
  • RecurringAccountViewModel.kt: Removal of fieldOfficerError, introduction of charge dialog/editing state, conditional template loading—verify no regressions in existing flows and correct charge state mutations.
  • CreateFixedDepositAccountScreen.kt: Propagation of state to all pages, wiring of MifosProgressIndicatorOverlay, removal of title/onBackPressed configuration; ensure overlay behavior and state passing are correct.

Possibly related PRs

Suggested reviewers

  • revanthkumarJ
  • TheKalpeshPawar

Poem

🐰 A form grows grand with many fields to fill,
State flows like streams down every step and sill,
Network checks guard the path ahead with care,
Validation blooms—no errors left to spare!
Spacing threads through layouts, neat and bright,
A deposit dance from left to right! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a new Settings step to the Fixed Deposits Account creation flow, which aligns with the substantial UI and state management updates in SettingsPage and related components.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/ChargesPage.kt (1)

90-124: Overdue charges button enablement is tied to the wrong state

In the overdue charges section:

if (state.loanTemplate?.overdueCharges?.isNotEmpty() ?: false) {
    ...
    btnEnabled = state.addedCharges.isNotEmpty(),
}

The "View" button for overdue charges is enabled based on state.addedCharges, not on the presence of overdue charges. This means users may be blocked from viewing overdue charges when there are none in addedCharges but some in overdueCharges.

Recommend enabling the button based on the same condition as the surrounding if:

-                    btnEnabled = state.addedCharges.isNotEmpty(),
+                    btnEnabled = state.loanTemplate?.overdueCharges?.isNotEmpty() ?: false,

The added Spacer below this block is fine and keeps the content visually separated from the bottom buttons.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (2)

781-795: Potential null pointer exception when adding charge to list.

The force-unwrap state.chooseChargeIndex!! on line 783 will throw if chooseChargeIndex is null. Consider adding a null check or using let to safely handle this case.

         RecurringAccountAction.AddChargeToList -> {
+            val chargeIndex = state.chooseChargeIndex ?: return
             val createdData = ChargeItem(
-                chargeId = state.template.chargeOptions?.get(state.chooseChargeIndex!!)?.id,
+                chargeId = state.template.chargeOptions?.get(chargeIndex)?.id,
                 amount = state.chargeAmount.toDoubleOrNull(),
             )

             mutableStateFlow.update {
                 it.copy(
                     addedCharges = it.addedCharges + createdData,
                     chooseChargeIndex = null,
                     dialogState = null,
                     chargeAmount = "",
                 )
             }
         }

714-730: EditCharge uses action.index incorrectly for both charge lookup and list update.

On line 716, action.index is used to get the charge from chargeOptions, but on line 721, it's used as the index into addedCharges. These are different lists with potentially different indices. The index from action.index should correspond to the position in addedCharges, not chargeOptions.

The charge ID should come from the currently selected chooseChargeIndex (which was set in EditChargeDialog), not from action.index:

         is RecurringAccountAction.EditCharge -> {
+            val chargeIndex = state.chooseChargeIndex ?: return
             val createdData = ChargeItem(
-                chargeId = state.template.chargeOptions?.get(action.index)?.id,
+                chargeId = state.template.chargeOptions?.get(chargeIndex)?.id,
                 amount = state.chargeAmount.toDoubleOrNull(),
             )

             val currentAddedCharges = state.addedCharges.toMutableList()
             currentAddedCharges[action.index] = createdData
🧹 Nitpick comments (4)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/ChargesPage.kt (1)

91-113: Double vertical spacing before bottom buttons

You now have both:

  • Spacer(Modifier.height(DesignToken.padding.large)) after MifosRowWithTextAndButton, and
  • MifosTwoButtonRow(..., modifier = Modifier.padding(top = DesignToken.padding.small)).

This will give more space above the buttons than similar pages that only use a Spacer or only top padding. If you’re aiming for consistent rhythm with the other Charges/Preview pages in this PR, consider dropping either the Spacer or the top padding (likely the top padding).

core/model/src/commonMain/kotlin/com/mifos/core/model/objects/template/recurring/MaturityInstructionOption.kt (1)

14-19: LGTM!

The data class is well-structured with nullable properties and appropriate defaults for safe deserialization. The @Serializable annotation enables kotlinx.serialization support.

Consider whether the package location (template.recurring) is semantically correct, given this class is also used by FixedDepositTemplate. If this is a shared template option, a more generic package like template.common might be more appropriate.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/SettingsPage.kt (1)

83-99: Use safe list access to prevent potential IndexOutOfBoundsException.

Direct list access via get(index) can throw an exception if the index is invalid. Consider using getOrNull for defensive coding, similar to how it's done in other pages.

             MifosTextFieldDropdown(
                 value = if (state.lockInPeriodTypeIndex != -1) {
-                    state.template.lockinPeriodFrequencyTypeOptions?.get(state.lockInPeriodTypeIndex)?.value.orEmpty()
+                    state.template.lockinPeriodFrequencyTypeOptions?.getOrNull(state.lockInPeriodTypeIndex)?.value.orEmpty()
                 } else {
                     ""
                 },

Apply the same pattern to other dropdown value bindings at lines 126, 162, 201, 241, and 298.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/TermsPage.kt (1)

110-129: Consider adding spacing between deposit period type dropdown and the next section.

The dropdown for deposit period type has Spacer(Modifier.height(DesignToken.padding.small)) after it (line 130), while other fields use DesignToken.padding.large. This creates inconsistent spacing before the "Interest Compounding" section header.

             label = stringResource(Res.string.feature_fixed_deposit_deposit_period_type) + "*",
             errorMessage = state.fixedDepositAccountTerms.depositPeriodTypeError?.let { stringResource(it) },
         )
-        Spacer(Modifier.height(DesignToken.padding.small))
+        Spacer(Modifier.height(DesignToken.padding.large))
         Text(
             text = stringResource(Res.string.feature_fixed_interest_compounding),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec227fc and f96db04.

📒 Files selected for processing (25)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/FixedDepositRepository.kt (1 hunks)
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/template/recurring/MaturityInstructionOption.kt (1 hunks)
  • core/network/src/commonMain/kotlin/com/mifos/core/network/model/FixedDepositTemplate.kt (2 hunks)
  • feature/client/src/commonMain/composeResources/values/strings.xml (1 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/ChargesPage.kt (1 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/DetailsPage.kt (0 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/PreviewPage.kt (2 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/TermsPage.kt (2 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountScreen.kt (6 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt (10 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/DetailsPage.kt (3 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/SettingsPage.kt (1 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/TermsPage.kt (2 hunks)
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/ChargesPage.kt (1 hunks)
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/PreviewPage.kt (2 hunks)
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/SchedulePage.kt (1 hunks)
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/TermsPage.kt (1 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (7 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt (1 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/DetailsPage.kt (1 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt (1 hunks)
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt (1 hunks)
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/DetailsPage.kt (0 hunks)
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/PreviewPage.kt (1 hunks)
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/TermsPage.kt (0 hunks)
💤 Files with no reviewable changes (3)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/DetailsPage.kt
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/DetailsPage.kt
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/TermsPage.kt
🧰 Additional context used
🧬 Code graph analysis (5)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/SettingsPage.kt (3)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosTextFieldDropdown.kt (1)
  • MifosTextFieldDropdown (39-112)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosCheckBox.kt (1)
  • MifosCheckBox (24-46)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosTwoButtonRow.kt (1)
  • MifosTwoButtonRow (31-91)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/TermsPage.kt (2)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosTextFieldDropdown.kt (1)
  • MifosTextFieldDropdown (39-112)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosTwoButtonRow.kt (1)
  • MifosTwoButtonRow (31-91)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/DetailsPage.kt (3)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosTextFieldDropdown.kt (1)
  • MifosTextFieldDropdown (39-112)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosOutlinedTextField.kt (1)
  • MifosDatePickerTextField (363-413)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosTwoButtonRow.kt (1)
  • MifosTwoButtonRow (31-91)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountScreen.kt (2)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosErrorComponent.kt (1)
  • MifosErrorComponent (41-60)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosProgressIndicator.kt (1)
  • MifosProgressIndicatorOverlay (70-102)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt (1)
  • loadRecurringAccountTemplateWithProduct (279-321)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR Checks / Static Analysis Check
🔇 Additional comments (36)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/PreviewPage.kt (2)

33-36: Imports for Spacer/height are correct and minimal

Spacer and height are both used exactly once and keep the imports set focused and consistent with Compose usage. No issues here.


82-93: Additional Spacer after charges row is reasonable

Placing Spacer(Modifier.height(DesignToken.padding.large)) inside the scrollable content column cleanly separates the charges section from the bottom action row without affecting logic or state. This aligns with token-based spacing and the broader layout pattern.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/SchedulePage.kt (1)

68-75: SchedulePage spacing addition looks good

The extra Spacer after RepaymentScheduleList keeps content visually separated from the bottom action row and is consistent with the rest of the flow. No functional impact.

feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt (1)

89-99: Savings ChargesPage spacer is consistent and safe

The added Spacer after the charges summary cleanly separates the list summary from the bottom action area and matches the spacing approach seen elsewhere in this PR. No issues.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/TermsPage.kt (1)

679-699: Collateral section spacing is appropriate

The Spacer after the collateral MifosRowWithTextAndButton adds clear separation from the bottom action row and aligns with the spacing approach elsewhere in the loan flow. Looks good.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt (1)

104-118: Recurring deposit ChargesPage spacing is consistent

The new Spacer after the charges summary row cleanly separates content from the bottom buttons and matches the pattern used in other account flows. No issues.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/PreviewPage.kt (1)

54-58: PreviewPage layout spacing change is sound

Adding Spacer(Modifier.height(DesignToken.padding.large)) after the charges MifosRowWithTextAndButton and relying on that instead of top padding on MifosTwoButtonRow gives a clear and consistent visual gap between content and actions. No behavioral concerns.

Also applies to: 188-201

feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/PreviewPage.kt (1)

172-197: Savings PreviewPage charges spacing looks correct

The added Spacer after the charges row provides consistent vertical separation from the bottom action row while preserving existing behavior. All good.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/TermsPage.kt (2)

227-228: LGTM!

The added spacing before the lock-in period section improves visual separation between form sections.


268-268: LGTM!

Adding large spacing at the end of the scrollable content ensures consistent bottom padding before the button row.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/DetailsPage.kt (1)

176-176: LGTM!

Removing the required indicator (*) from the field officer label aligns with the updated validation logic where field officer is no longer a required field.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt (1)

101-101: LGTM!

Adding the spacer at the end of the scrollable content maintains consistent spacing before the button row, aligning with the layout pattern used in other pages.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountScreen.kt (3)

56-61: LGTM!

Clean refactoring from newFixedDepositAccountState to state improves readability and aligns with common naming conventions for state-driven Compose components.


86-91: LGTM!

Properly wiring SettingPage with both state and onAction enables state-driven UI and action dispatching, consistent with the updated component signature.


137-139: LGTM!

The progress overlay provides clear visual feedback during async operations. Placing it at the end of the scaffold content ensures it renders above other content when active.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/SettingsPage.kt (3)

54-67: LGTM!

The refactored signature to accept state and onAction aligns with the state-driven architecture used across other page components in this flow. The layout structure with scrollable content and fixed button row is well-organized.


274-316: LGTM!

Good use of AnimatedVisibility to conditionally show penal interest fields. This provides a smooth UX when the user toggles the checkbox.


319-324: LGTM!

The two-button row correctly dispatches PreviousStep and OnNextPress actions for step navigation.

core/network/src/commonMain/kotlin/com/mifos/core/network/model/FixedDepositTemplate.kt (1)

57-58: Add @SerialName annotations for consistency and safety.

The new properties lack @SerialName annotations, unlike other properties in this class. This could cause deserialization failures if the API JSON keys differ from the Kotlin property names (e.g., snake_case vs camelCase).

core/data/src/commonMain/kotlin/com/mifos/core/data/repository/FixedDepositRepository.kt (1)

17-20: Verify all implementations handle the optional productId parameter correctly.

Adding a default value to an interface parameter requires updating all implementations. Ensure the implementation(s) of FixedDepositRepository correctly handle null values for productId when constructing API requests. Search the codebase for all classes implementing this interface and verify their getFixedDepositTemplate method properly handles the null case.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/TermsPage.kt (4)

54-57: Good layout structure with weighted scrollable content.

The two-tiered column approach correctly separates the scrollable content from the fixed bottom navigation. The outer modifier is applied correctly to the inner column.


63-88: Deposit amount field with proper validation and currency prefix.

The field correctly displays the currency symbol prefix, required indicator, and error handling. The error text is properly resolved via stringResource.


136-212: Interest compounding dropdowns are consistently implemented.

The pattern of checking index != -1 before accessing options and falling back to empty string is correct. The onValueChanged = {} is appropriate since these are read-only dropdowns.


214-219: Navigation buttons correctly wired to new action names.

The Back button triggers PreviousStep and Next button triggers OnTermNext, aligning with the updated action structure in the ViewModel.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/DetailsPage.kt (4)

98-105: Consistent layout structure with TermsPage.

The two-tiered column approach with weighted scrollable content and fixed bottom navigation matches the pattern established in TermsPage.


107-123: Product dropdown correctly bound to state with error handling.

The dropdown properly displays product options and handles product selection errors.


125-169: Verify: Submission date and external ID hidden when no field officers available.

The conditional block if (!state.template.fieldOfficerOptions.isNullOrEmpty()) hides the submission date picker, field officer dropdown, and external ID field when fieldOfficerOptions is null or empty. This means these fields won't be visible until a product is selected and the product-specific template is loaded.

Is this the intended UX? The submission date might be needed regardless of field officer availability.


171-177: Navigation properly wired with OnDetailNext action.

The second button correctly triggers OnDetailNext for validation before proceeding.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (3)

159-168: Conditional template loading when field officers not available.

The logic to reload template with product only when fieldOfficerOptions is null is consistent with the Fixed Deposit flow pattern.


630-646: OnDetailNext validates only product selection.

The removal of fieldOfficerError validation simplifies the flow, requiring only product selection to proceed.


823-828: DialogState sealed interface correctly extended.

The new ShowCharges state is properly added alongside existing dialog states.

feature/client/src/commonMain/composeResources/values/strings.xml (1)

608-622: New Fixed Deposit settings strings added with consistent naming.

The string resources follow the established naming convention and provide appropriate labels for the settings UI. The %% escape for the percent sign in "Penal Interest (%%)" is correct for Android/Compose resources.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt (4)

237-276: Network-aware template loading with proper error handling.

The implementation correctly checks network availability before making API calls and provides user-friendly error messages when offline.


96-133: Validation logic for OnDetailNext and OnTermNext is well-structured.

The validation properly checks required fields and updates error state before allowing navigation to proceed.


139-229: New settings state update handlers are consistent.

All the new action handlers for settings fields follow the same pattern and correctly update state.


487-503: New settings state fields added to support the Settings step.

The additional state fields for lock-in period, deposit terms, maturity instructions, and penal interest settings are properly typed and initialized with sensible defaults.

Comment on lines +279 to 321
private fun loadRecurringAccountTemplateWithProduct() = viewModelScope.launch {
if (networkMonitor.isOnline.first()) {
fixedDepositRepository.getFixedDepositTemplate(
clientId = state.clientId,
productId = state.template.productOptions?.get(state.fixedDepositAccountDetail.productSelected)?.id,
).collect { state ->
when (state) {
is DataState.Success -> {
mutableStateFlow.update {
it.copy(
screenState = NewFixedDepositAccountState.ScreenState.Success,
isOverlayLoading = false,
template = state.data,
)
}
}

is DataState.Error -> {
mutableStateFlow.update {
it.copy(
screenState = NewFixedDepositAccountState.ScreenState.Error(state.message),
isOverlayLoading = false,
)
}
}

DataState.Loading -> {
mutableStateFlow.update {
it.copy(
isOverlayLoading = true,
)
}
}
}
}
} else {
mutableStateFlow.update {
it.copy(
screenState = NewFixedDepositAccountState.ScreenState.Error(getString(Res.string.feature_client_error_network_not_available)),
)
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Function name doesn't match its purpose.

The function is named loadRecurringAccountTemplateWithProduct but it loads a Fixed Deposit template using fixedDepositRepository.getFixedDepositTemplate(). This appears to be a copy-paste issue from the RecurringAccountViewModel.

-    private fun loadRecurringAccountTemplateWithProduct() = viewModelScope.launch {
+    private fun loadFixedDepositTemplateWithProduct() = viewModelScope.launch {

Also update the call site on line 357:

     if (state.template.fieldOfficerOptions == null) {
-        loadRecurringAccountTemplateWithProduct()
+        loadFixedDepositTemplateWithProduct()
     }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt
around lines 279-321, the function is misnamed
`loadRecurringAccountTemplateWithProduct` though it loads a Fixed Deposit
template; rename the function to something accurate (e.g.,
`loadFixedDepositTemplateWithProduct`) and update its declaration and all call
sites (including the call on line 357) to the new name so the name matches its
behavior and avoids copy-paste confusion.

Comment on lines +371 to 378
private fun moveToPreviousStep() {
val current = state.currentStep
mutableStateFlow.update {
it.copy(
fixedDepositAccountDetail = it.fixedDepositAccountDetail.copy(
externalId = action.value,
),
currentStep = current - 1,
)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing bounds check in moveToPreviousStep.

The function decrements currentStep without checking if it's already at 0, which could result in a negative step index.

     private fun moveToPreviousStep() {
         val current = state.currentStep
+        if (current <= 0) return
         mutableStateFlow.update {
             it.copy(
                 currentStep = current - 1,
             )
         }
     }
🤖 Prompt for AI Agents
In
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt
around lines 371 to 378, moveToPreviousStep() decrements currentStep without
bounds checking which can produce a negative index; modify the function to check
currentStep > 0 (or clamp to 0) before decrementing — either return early if
currentStep is 0 or set currentStep = maxOf(0, current - 1) when updating
mutableStateFlow so the step never becomes negative.

Comment on lines 574 to 591
sealed class NewFixedDepositAccountTermsAction : NewFixedDepositAccountAction() {
data class SetFixedDepositAmount(val depositAmount: String) : NewFixedDepositAccountAction()
data class SetFixedDepositPeriod(val period: String) : NewFixedDepositAccountAction()
data class SetFixedDepositPeriodType(val depositPeriodTypeIndex: Int) : NewFixedDepositAccountAction()
data class SetInterestCompoundingPeriod(val interestCompoundingPeriodTypeIndex: Int) : NewFixedDepositAccountAction()
data class SetInterestPostingPeriod(val interestPostingPeriodTypeIndex: Int) : NewFixedDepositAccountAction()
data class SetInterestCalculationType(val interestCalculationPeriodTypeIndex: Int) : NewFixedDepositAccountAction()
data class SetInterestCalculationDaysInYearType(val periodTypeIndex: Int) : NewFixedDepositAccountAction()
data class SetFixedDepositPeriodType(val depositPeriodTypeIndex: Int) :
NewFixedDepositAccountAction()

data class SetInterestCompoundingPeriod(val interestCompoundingPeriodTypeIndex: Int) :
NewFixedDepositAccountAction()

data class SetInterestPostingPeriod(val interestPostingPeriodTypeIndex: Int) :
NewFixedDepositAccountAction()

data class SetInterestCalculationType(val interestCalculationPeriodTypeIndex: Int) :
NewFixedDepositAccountAction()

data class SetInterestCalculationDaysInYearType(val periodTypeIndex: Int) :
NewFixedDepositAccountAction()
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Nested action classes extend wrong parent type.

The action classes inside NewFixedDepositAccountTermsAction sealed class extend NewFixedDepositAccountAction() directly instead of NewFixedDepositAccountTermsAction(). This breaks the sealed class hierarchy and means these actions won't match is NewFixedDepositAccountAction.NewFixedDepositAccountTermsAction patterns correctly.

     sealed class NewFixedDepositAccountTermsAction : NewFixedDepositAccountAction() {
-        data class SetFixedDepositAmount(val depositAmount: String) : NewFixedDepositAccountAction()
-        data class SetFixedDepositPeriod(val period: String) : NewFixedDepositAccountAction()
-        data class SetFixedDepositPeriodType(val depositPeriodTypeIndex: Int) :
-            NewFixedDepositAccountAction()
-
-        data class SetInterestCompoundingPeriod(val interestCompoundingPeriodTypeIndex: Int) :
-            NewFixedDepositAccountAction()
-
-        data class SetInterestPostingPeriod(val interestPostingPeriodTypeIndex: Int) :
-            NewFixedDepositAccountAction()
-
-        data class SetInterestCalculationType(val interestCalculationPeriodTypeIndex: Int) :
-            NewFixedDepositAccountAction()
-
-        data class SetInterestCalculationDaysInYearType(val periodTypeIndex: Int) :
-            NewFixedDepositAccountAction()
+        data class SetFixedDepositAmount(val depositAmount: String) : NewFixedDepositAccountTermsAction()
+        data class SetFixedDepositPeriod(val period: String) : NewFixedDepositAccountTermsAction()
+        data class SetFixedDepositPeriodType(val depositPeriodTypeIndex: Int) :
+            NewFixedDepositAccountTermsAction()
+
+        data class SetInterestCompoundingPeriod(val interestCompoundingPeriodTypeIndex: Int) :
+            NewFixedDepositAccountTermsAction()
+
+        data class SetInterestPostingPeriod(val interestPostingPeriodTypeIndex: Int) :
+            NewFixedDepositAccountTermsAction()
+
+        data class SetInterestCalculationType(val interestCalculationPeriodTypeIndex: Int) :
+            NewFixedDepositAccountTermsAction()
+
+        data class SetInterestCalculationDaysInYearType(val periodTypeIndex: Int) :
+            NewFixedDepositAccountTermsAction()
     }
🤖 Prompt for AI Agents
In
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt
around lines 574-591, the nested action data classes inside the sealed class
NewFixedDepositAccountTermsAction mistakenly extend NewFixedDepositAccountAction
instead of extending NewFixedDepositAccountTermsAction; update each nested data
class declaration so it extends NewFixedDepositAccountTermsAction() (i.e.,
replace NewFixedDepositAccountAction() with NewFixedDepositAccountTermsAction())
ensuring the sealed hierarchy is correct and pattern matching against
NewFixedDepositAccountAction.NewFixedDepositAccountTermsAction works as
intended.

Comment on lines +108 to +122
MifosOutlinedTextField(
value = state.minimumDispositTermFrequency,
onValueChange = {
onAction(
NewFixedDepositAccountAction.OnMinimumDepositTermFrequencyChange(it),
)
},
label = stringResource(Res.string.feature_fixed_deposit_setting_thereafter_in_multiples),
config = MifosTextFieldConfig(
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next,
),
),
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Possible label mismatch for minimum deposit term frequency field.

The field uses feature_fixed_deposit_setting_thereafter_in_multiples as the label (line 115), but this appears to be the "Minimum Deposit Term" frequency input based on the section header (line 103) and the action OnMinimumDepositTermFrequencyChange.

Verify this is intentional or consider using a more appropriate label like feature_fixed_deposit_setting_frequency.

             MifosOutlinedTextField(
                 value = state.minimumDispositTermFrequency,
                 onValueChange = {
                     onAction(
                         NewFixedDepositAccountAction.OnMinimumDepositTermFrequencyChange(it),
                     )
                 },
-                label = stringResource(Res.string.feature_fixed_deposit_setting_thereafter_in_multiples),
+                label = stringResource(Res.string.feature_fixed_deposit_setting_frequency),
                 config = MifosTextFieldConfig(

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/SettingsPage.kt
around lines 108 to 122, the TextField for minimum deposit term frequency uses
the label resource feature_fixed_deposit_setting_thereafter_in_multiples which
likely mismatches the field purpose; update the label to the correct resource
(e.g., feature_fixed_deposit_setting_frequency or another appropriate string) so
it matches the OnMinimumDepositTermFrequencyChange action and section header,
and ensure the chosen string resource exists and is used consistently across the
form.

@therajanmaurya therajanmaurya merged commit 48b1dee into openMF:development Dec 9, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants