Skip to content

Conversation

@Arinyadav1
Copy link
Contributor

@Arinyadav1 Arinyadav1 commented Dec 7, 2025

Fixes - Jira-#554

Screenshot 2025-12-07 200036 Screenshot 2025-12-07 200054 Screenshot 2025-12-07 200120

Summary by CodeRabbit

Release Notes

  • New Features

    • Added charge management functionality across account creation flows with dialog-based add/edit/view capabilities.
    • Introduced empty state messaging when no charges are present, prompting users to add charges.
  • Bug Fixes

    • Improved charge list state management during delete operations.
    • Enhanced dialog dismiss behavior.
  • Style

    • Added visual indicators (asterisks) for required form fields.
    • Adjusted layout spacing and padding for better UI consistency.
  • Chores

    • Added localization strings for charge management workflows across multiple account types.

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

@coderabbitai
Copy link

coderabbitai bot commented Dec 7, 2025

Walkthrough

This pull request introduces charge management functionality across multiple feature modules (recurring deposits, savings, loan, client) by adding typed charge models, state management, and UI dialogs for creating, editing, and viewing charges. The changes include a new ChargeItem data class, updates to payload structures, new dialog components, and supporting string resources.

Changes

Cohort / File(s) Summary
Core Model Updates
core/database/src/.../RecurringDepositAccountTemplate.kt, core/model/src/.../RecurringDepositAccountPayload.kt
Removed untyped charges field from RecurringDepositAccountTemplate; introduced typed ChargeItem data class and updated RecurringDepositAccountPayload.charges to use List<ChargeItem>?
String Resources
feature/client/src/.../strings.xml, feature/loan/src/.../strings.xml, feature/recurringDeposit/src/.../feature_recurring_deposit_string.xml, feature/savings/src/.../feature_savings_strings.xml
Added UI text resources for charge management workflows: "Click on Add New to Add Charge" and related charge dialog labels across all affected modules
Share Account Creation UI
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt, feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/ChargesPage.kt, feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/TermsPage.kt
Updated charge dialog to show empty state when no charges added; added bottom padding to charges page; appended asterisks to required field labels
Loan Account UI
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt
Updated dialog dismiss text and added conditional rendering of charges list with empty state card; resets expanded index on charge deletion
Recurring Deposit Feature
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt, feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt, feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt
Comprehensive charge management implementation: added AddNewChargeDialog and ShowChargesDialog composables; extended ViewModel with charge-related state fields (addedCharges, chargeAmount, chooseChargeIndex) and actions; redesigned ChargesPage from simple callback to state-driven UI with full dialog integration
Savings Account UI
feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt, feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt
Refactored charge dialog from LazyColumn to Column rendering with conditional empty state; updated imports and dismiss text; removed top padding from button row in charges page

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Areas requiring extra attention:

  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt — Complete redesign from simple callback to state-driven UI with multiple dialog integrations and expanded item management
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt — Multiple new state fields and action types for charge lifecycle management; ensure payload construction includes charges correctly
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt — Layout refactoring from LazyColumn to Column; verify empty state rendering and button row positioning
  • Consistency of charge management patterns across all modules (loan, client, savings, recurring deposits)

Possibly related PRs

Suggested reviewers

  • TheKalpeshPawar
  • revanthkumarJ
  • biplab1

Poem

🐰 A rabbit hops through charges new,
Adding dialogs, states anew,
From recurring dreams to savings true,
Each feature shines in structured hue! ✨

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 clearly and concisely describes the main objective of the pull request: implementing a charges step in the new recurring deposits account creation flow.
✨ 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: 3

Caution

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

⚠️ Outside diff range comments (1)
feature/loan/src/commonMain/composeResources/values/strings.xml (1)

231-231: Fix malformed XML closing tag on principle_paid_off

The line

<string name="principle_paid_off">Principle Paid Off</string">

has an extra " after </string>, which will cause XML/resource compilation to fail. Remove the trailing quote so it becomes:

<string name="principle_paid_off">Principle Paid Off</string>
🧹 Nitpick comments (6)
feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt (2)

308-308: Consider renaming expandedIndex to expandedChargeId for clarity.

The variable stores a charge's id (used on lines 352, 354), not its index. The current name expandedIndex is misleading.

-    var expandedIndex: Int? by rememberSaveable { mutableStateOf(-1) }
+    var expandedChargeId: Int? by rememberSaveable { mutableStateOf(-1) }

358-362: Consider customizing the MifosEmptyCard title for better context.

The default title is "No item found". A more specific title would improve UX in the charges context.

                 MifosEmptyCard(
+                    title = "No Charges",
                     msg = stringResource(Res.string.feature_savings_charges_click_on_add_new),
                 )

Note: Consider adding a string resource for the title if localization is needed.

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

110-112: Consider using a string resource with placeholder for proper i18n.

The string concatenation state.addedCharges.size.toString() + " " + stringResource(...) may cause localization issues in languages where word order differs. Consider defining a string resource with a %d placeholder like "%d Active Charges".

feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml (1)

65-73: LGTM!

The new string resources follow the established naming convention and provide appropriate UI text for the charge management functionality. Consider adding a pluralized version of feature_recurring_deposit_active_charge (e.g., "Active Charges") or using a format string with count placeholder for better grammatical correctness.

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

224-224: Tighten the helper text phrasing for better UX

The new copy works but reads a bit awkwardly. Consider a more natural phrasing such as:

<string name="click_on_add_new">Click "Add New" to add a charge</string>

This matches common UI wording and keeps “Add New” visually distinct as the control label.

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

486-521: Good empty-state UX and safer expansion behavior for charges list

  • Guarding on state.addedCharges.isNotEmpty() and showing MifosEmptyCard with click_on_add_new provides a clear, guided empty state instead of a blank list.
  • Resetting expandedIndex = -1 before deleting a charge prevents the next item in the list from appearing “mysteriously” expanded after indices shift.

If you ever revisit this, you could slightly simplify the state by making expandedIndex a non-null Int (no ?) with -1 as the “no selection” sentinel, to better reflect how it’s used. Not required for correctness.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8f7247 and 72d8f88.

📒 Files selected for processing (15)
  • core/database/src/commonMain/kotlin/com/mifos/room/entities/templates/recurringDeposit/RecurringDepositAccountTemplate.kt (0 hunks)
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt (2 hunks)
  • feature/client/src/commonMain/composeResources/values/strings.xml (1 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt (5 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/TermsPage.kt (2 hunks)
  • feature/loan/src/commonMain/composeResources/values/strings.xml (1 hunks)
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt (4 hunks)
  • feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml (1 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt (3 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (6 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt (1 hunks)
  • feature/savings/src/commonMain/composeResources/values/feature_savings_strings.xml (1 hunks)
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt (4 hunks)
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt (0 hunks)
💤 Files with no reviewable changes (2)
  • core/database/src/commonMain/kotlin/com/mifos/room/entities/templates/recurringDeposit/RecurringDepositAccountTemplate.kt
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/pages/ChargesPage.kt
🧰 Additional context used
🧬 Code graph analysis (4)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt (2)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosActionsListingCardComponent.kt (1)
  • MifosActionsChargeListingComponent (601-735)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosEmptyCard.kt (1)
  • MifosEmptyCard (28-49)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt (4)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt (2)
  • AddNewChargeDialog (217-272)
  • ShowChargesDialog (274-346)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt (2)
  • AddNewChargeDialog (380-447)
  • ShowChargesDialog (449-538)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt (2)
  • AddNewChargeDialog (128-183)
  • ShowChargesDialog (185-258)
feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt (2)
  • AddNewChargeDialog (217-301)
  • ShowChargesDialog (303-376)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt (2)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosActionsListingCardComponent.kt (1)
  • MifosActionsChargeListingComponent (601-735)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosEmptyCard.kt (1)
  • MifosEmptyCard (28-49)
feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt (3)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosActionsListingCardComponent.kt (1)
  • MifosActionsChargeListingComponent (601-735)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosEmptyCard.kt (1)
  • MifosEmptyCard (28-49)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosTwoButtonRow.kt (1)
  • MifosTwoButtonRow (31-91)
⏰ 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 (16)
feature/savings/src/commonMain/composeResources/values/feature_savings_strings.xml (1)

149-150: LGTM!

The new string resource follows the existing naming convention and provides clear guidance for the empty charges state.

feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountScreen.kt (3)

14-14: LGTM!

Import changes align with the updated usage in ShowChargesDialog for empty state handling.

Also applies to: 53-53


247-247: LGTM!

Using "Back" instead of "Cancel" provides consistent navigation terminology across the charge dialogs.


315-373: LGTM!

The dialog layout refactor is well-structured:

  • Clean separation between header, content, and action buttons
  • Proper empty state handling with MifosEmptyCard
  • MifosTwoButtonRow correctly positioned outside the items loop
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/TermsPage.kt (1)

141-141: LGTM! Good UX improvement to indicate required fields.

Appending asterisks to mark required fields aligns with common form validation patterns and is consistent with the existing error handling for totalSharesError and savingsAccountError in the state.

Also applies to: 165-165

feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/pages/ChargesPage.kt (1)

52-52: LGTM! Consistent layout adjustment.

The addition of bottom padding to the outer Column aligns with the same pattern used in other pages (e.g., TermsPage.kt line 108) within the CreateShareAccount flow.

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

586-586: LGTM! Clear empty-state message.

The new string resource provides appropriate guidance to users when no charges have been added yet.

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

17-17: LGTM! Imports properly utilized.

The new imports for feature_share_account_charge_click_on_add_new and MifosEmptyCard are correctly used in the ShowChargesDialog function for empty-state rendering.

Also applies to: 52-52


294-331: LGTM! Well-implemented empty state handling.

The conditional rendering properly handles both populated and empty charge lists:

  • When charges exist, displays the expandable list with edit/delete actions
  • When empty, shows an appropriate empty-state card with guidance
  • Resetting expandedIndex = -1 before deletion (line 306) prevents potential stale-state issues after items are removed
core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt (1)

43-47: LGTM!

The ChargeItem data class is clean and properly annotated with @Serializable. Consider whether a ChargeItem with null chargeId should be allowed to be added to the list, as this could result in invalid payload data being sent to the server.

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

88-102: LGTM!

The dialog state handling for AddNewCharge and ShowCharges follows the established pattern and correctly passes the required parameters. The implementation aligns with similar dialog patterns in other screens (CreateShareAccount, Savings, Loan) per the relevant code snippets.


140-143: LGTM!

The updated ChargesPage invocation correctly passes the full state and action handler, enabling the state-driven UI pattern used throughout the application.

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

177-178: Empty date handlers are intentional.

The empty lambdas for onDatePick and onDateChange appear intentional since recurring deposit charges may not require date selection, consistent with patterns in similar screens.

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

809-811: LGTM!

The new state fields for charge management (addedCharges, chargeAmount, chooseChargeIndex) are properly defined with sensible defaults.


917-924: LGTM!

The new action types for charge management are well-defined and follow the existing action pattern in the codebase.

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

387-399: Dismiss label change to “Back” looks consistent with other dialogs

Switching dismissText to back aligns this bottom sheet with ShowCollateralsDialog and the rest of the stepper-style flow, keeping navigation language consistent. No issues from a behavior standpoint.

chargeTitle = chargesValue?.name ?: "",
type = chargesValue?.chargeCalculationType?.value ?: "",
collectedOn = chargesValue?.chargeTimeType?.value ?: "",
amount = charge.amount.toString(),
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

Handle potential null amount display.

If charge.amount is null, calling .toString() will display "null" to the user. Consider providing a fallback value.

-                            amount = charge.amount.toString(),
+                            amount = charge.amount?.toString() ?: "0.0",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
amount = charge.amount.toString(),
amount = charge.amount?.toString() ?: "0.0",
🤖 Prompt for AI Agents
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt
around line 214: the code currently uses charge.amount.toString(), which will
render "null" if amount is null; replace this with a null-safe display that uses
a fallback (e.g., empty string, localized "—", or formatted "0.00") and
preferably format numbers consistently (use charge.amount?.let {
formatDecimal(it) } ?: fallback) so users never see the literal "null".

Comment on lines +714 to +730
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 = "",
)
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: Incorrect index used for chargeId lookup in EditCharge.

The action.index represents the index in addedCharges list, but it's being used to index into chargeOptions. This will result in the wrong chargeId being assigned when editing a charge.

The correct implementation should use state.chooseChargeIndex (which was set by EditChargeDialog based on the selected charge) to look up the chargeId from chargeOptions.

 is RecurringAccountAction.EditCharge -> {
     val createdData = ChargeItem(
-        chargeId = state.template.chargeOptions?.get(action.index)?.id,
+        chargeId = state.chooseChargeIndex?.let { state.template.chargeOptions?.get(it)?.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 = "",
         )
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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.EditCharge -> {
val createdData = ChargeItem(
chargeId = state.chooseChargeIndex?.let { state.template.chargeOptions?.get(it)?.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 = "",
)
}
}
🤖 Prompt for AI Agents
In
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt
around lines 714-730, the code uses action.index to read from
state.template.chargeOptions which is wrong because action.index is the index
into addedCharges, not chargeOptions; change the lookup to use
state.chooseChargeIndex (which EditChargeDialog sets) when retrieving the
chargeId from chargeOptions, while still using action.index to update the
addedCharges list. Also add a null/bounds guard: resolve an indexToUse =
state.chooseChargeIndex ?: action.index and ensure it’s within chargeOptions
bounds before accessing id to avoid NPE/IndexOutOfBounds.

Comment on lines +776 to +790
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 = "",
)
}
}
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

Potential crash from force-unwrap of nullable index.

Using state.chooseChargeIndex!! on line 778 will throw a NullPointerException if chooseChargeIndex is null. While the UI flow should prevent this, defensive coding is recommended.

 RecurringAccountAction.AddChargeToList -> {
+    val chargeIndex = state.chooseChargeIndex ?: return@handleAction
     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 = "",
         )
     }
 }
🤖 Prompt for AI Agents
In
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt
around lines 776 to 790, the code force-unwraps state.chooseChargeIndex (!!)
which can throw if null; change to a safe-check/early-return or use let with
getOrNull to safely obtain the charge option before creating ChargeItem, e.g.,
guard that chooseChargeIndex is not null and within bounds (or use
state.template.chargeOptions?.getOrNull(index)) and only update the state when a
valid chargeId is obtained, otherwise clear dialog/inputs or log/handle the
invalid case without throwing.

@therajanmaurya therajanmaurya enabled auto-merge (squash) December 7, 2025 22:08
@therajanmaurya therajanmaurya merged commit ec227fc into openMF:development Dec 7, 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