Skip to content

feat(loan): implement loan charge-off screen#2696

Merged
revanthkumarJ merged 2 commits into
openMF:devfrom
sahilshivekar:charge-off-screen
Jul 2, 2026
Merged

feat(loan): implement loan charge-off screen#2696
revanthkumarJ merged 2 commits into
openMF:devfrom
sahilshivekar:charge-off-screen

Conversation

@sahilshivekar

@sahilshivekar sahilshivekar commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Fixes - Jira-#690

Before After
charge_off_not_implemented.mp4
charge_off_success.mp4

Note:
Loan Account Action Screen is reloaded because if the charge-off operation is successful then it needs to show Undo Charge-off instead of Charge-off

In Loan Account Action Item property with name "id" is added because StringResource (item.title) is not supported as a key for lazy column on android platform. It throws exception ->
java.lang.IllegalArgumentException: Type of the key org.jetbrains.compose.resources.StringResource@3aecd81e is not supported. On Android you can only use types which can be stored inside the Bundle.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8810919d-bbc9-4279-a8c6-4c64e4b278a7

📥 Commits

Reviewing files that changed from the base of the PR and between c25c091 and 42c71b9.

📒 Files selected for processing (1)
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: PR Checks / Static Analysis Check

Summary by CodeRabbit

  • New Features

    • Added a new loan charge-off flow with template loading, reason selection, date entry, optional external ID and note fields, and submit confirmation.
    • Added navigation support and a new charge-off action in loan screens.
    • Introduced new status and charge-off string resources plus a dedicated charge-off icon.
  • Bug Fixes

    • Improved list item stability in loan action screens for smoother updates and recomposition.

Walkthrough

Adds a loan charge-off flow with new models, network API wiring, repository and domain layers, a charge-off screen and view model, and navigation entry points integrated into loan actions.

Changes

Loan Charge Off Feature

Layer-by-layer breakdown
Layer / File(s) Summary
Models and network API
ChargeOffReasonOption.kt, LoanChargeOffInput.kt, LoanChargeOffRequestDto.kt, LoanChargeOffResponseDto.kt, LoanChargeOffTemplateDto.kt, LoanService.kt, DataManagerLoan.kt
Adds charge-off model classes, serializable request/response/template DTOs, new LoanService endpoints, DataManagerLoan methods, and JSON decoding formatting changes.
Repository and domain wiring
ChargeOffReasonOptionMapper.kt, LoanChargeOffInputMapper.kt, LoanChargeOffRepository.kt, LoanChargeOffRepositoryImpl.kt, GetLoanChargeOffTemplateUseCase.kt, LoanChargeOffUseCase.kt, RepositoryModule.kt, UseCaseModule.kt
Adds DTO-to-model mappers, the charge-off repository interface and implementation, two domain use cases, and Koin registrations for repository and use cases.
Charge-off UI state and screen
LoanChargeOffState.kt, LoanChargeOffViewModel.kt, LoanChargeOffScreen.kt, MifosIcons.kt, charge_off.xml, strings.xml
Adds the charge-off state model, view model contracts and logic, Compose screen content, the charge-off icon and drawable, and new string resources.
Navigation entry points
LoanChargeOffScreenRoute.kt, LoanModule.kt, LoanAccountActionNavigation.kt, LoanAccountActionItem.kt, LoanAccountActionScreen.kt, LoanActionPaymentsScreen.kt, LoanNavigation.kt, LoanAccountProfileNavigation.kt, LoanAccountProfileScreen.kt
Adds the charge-off route and navigation helper, registers the screen and view model in Koin, wires the loan account action item and callbacks, and updates loan profile screen parameter ordering.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

Charge-off submission flow
sequenceDiagram
  participant User
  participant LoanChargeOffScreen
  participant LoanChargeOffViewModel
  participant LoanChargeOffUseCase
  participant LoanChargeOffRepository
  participant DataManagerLoan

  User->>LoanChargeOffScreen: opens screen with loanId
  LoanChargeOffScreen->>LoanChargeOffViewModel: init and loadTemplate()
  LoanChargeOffViewModel->>LoanChargeOffUseCase: getChargeOffTemplate(loanId)
  LoanChargeOffUseCase->>LoanChargeOffRepository: getChargeOffTemplate(loanId)
  LoanChargeOffRepository->>DataManagerLoan: getChargeOffTemplate(loanId)
  DataManagerLoan-->>LoanChargeOffRepository: template DTO
  LoanChargeOffRepository-->>LoanChargeOffViewModel: DataState<List<ChargeOffReasonOption>>

  User->>LoanChargeOffScreen: selects reason and submits
  LoanChargeOffScreen->>LoanChargeOffViewModel: Submit
  LoanChargeOffViewModel->>LoanChargeOffUseCase: chargeOff(loanId, LoanChargeOffInput)
  LoanChargeOffUseCase->>LoanChargeOffRepository: chargeOff(loanId, LoanChargeOffInput)
  LoanChargeOffRepository->>DataManagerLoan: chargeOff(loanId, requestDto)
  DataManagerLoan-->>LoanChargeOffRepository: response DTO
  LoanChargeOffRepository-->>LoanChargeOffViewModel: DataState<Unit>
  LoanChargeOffViewModel-->>LoanChargeOffScreen: dialog / success event
Loading

Possibly related PRs

Suggested reviewers: revanthkumarJ, niyajali, Nagarjuna0033


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Jira Link And Before/After Sections ❌ Error The Jira link is present, but the description has a table instead of literal Before:/After: sections, so the required sections are missing. Rewrite the PR description with separate 'Before:' and 'After:' headings, and include image/video media under each section.
Docstring Coverage ⚠️ Warning Docstring coverage is 2.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required format and clearly summarizes the loan charge-off screen work.
Description check ✅ Passed The description is directly related to the charge-off screen, reload behavior, and LazyColumn key fix.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@sahilshivekar sahilshivekar force-pushed the charge-off-screen branch 4 times, most recently from 16c4458 to da0d6ac Compare July 1, 2026 10:37
@sahilshivekar sahilshivekar marked this pull request as ready for review July 1, 2026 10:46
@sahilshivekar sahilshivekar requested a review from a team July 1, 2026 10:46
revanthkumarJ
revanthkumarJ previously approved these changes Jul 1, 2026
@revanthkumarJ

Copy link
Copy Markdown
Contributor

@sahilshivekar upload video or screenshots

@sahilshivekar

Copy link
Copy Markdown
Contributor Author

@sahilshivekar upload video or screenshots

@revanthkumarJ The app isn't working now. Server is responding with status code 502

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt (1)

391-395: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Wire the visible ChargeOff action to navigation

LoanAccountActionViewModel.kt still emits LoanAccountActionItem.ChargeOff, but LoanAccountActionNavigation.kt maps that case to {} while only LoanChargeOff is routed. Tapping the charge-off row does nothing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt`
around lines 391 - 395, The visible ChargeOff action is emitted by
LoanAccountActionViewModel but has no navigation target, so tapping it is a
no-op. Update LoanAccountActionNavigation to handle
LoanAccountActionItem.ChargeOff the same way the existing LoanChargeOff route is
handled, and ensure the ChargeOff action in LoanAccountActionItem is wired to
the actual charge-off destination instead of an empty block.
🧹 Nitpick comments (3)
core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt (1)

14-21: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse the shared short-date constant

LoanChargeOffInput.kt hardcodes "dd-MM-yyyy", while DateHelper.kt already defines the same pattern as SHORT_MONTH. Reuse that constant, or add one alongside DateConstants.DATE_FORMAT, so the request stays aligned with the rest of the date-format definitions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt`
around lines 14 - 21, LoanChargeOffInput currently hardcodes the short date
pattern, so update the LoanChargeOffInput data class to reuse the shared
date-format constant instead of repeating the literal. Use the existing
DateHelper/DateConstants symbols already in the codebase, such as SHORT_MONTH or
a shared constant alongside DateConstants.DATE_FORMAT, and replace the default
dateFormat value in LoanChargeOffInput with that shared reference.
core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt (1)

118-128: 📐 Maintainability & Code Quality | 🔵 Trivial

Heads up: this is a core module — extra scrutiny time. 🎩

These new chargeOff/getChargeOffTemplate methods land in DataManagerLoan.kt, a shared foundational core module consumed by every downstream feature. Nothing wrong with the code itself, just flagging per path instructions that core-module changes deserve careful review attention since ripple effects are wide-reaching (this note applies to the whole cohort under core/, not just this file).

As per path instructions, "Changes in core-base module must be treated as high-impact... Clearly highlight that core-base is a shared foundational module and requires extra review attention."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt`
around lines 118 - 128, The new getChargeOffTemplate and chargeOff additions in
DataManagerLoan are in a shared core module and should be treated as high-impact
changes. Update the surrounding module/documentation or PR notes to explicitly
call out that DataManagerLoan and its new loanService passthroughs affect
downstream consumers across the app, so they require extra review attention and
regression checking.

Source: Path instructions

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt (1)

167-188: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract DatePickerDialog into its own composable.

The date-picker dialog is embedded inline inside LoanChargeOffForm, which also renders the dropdown, text fields, and submit button. Per UI structure guidelines, dialogs should be separated into their own composables rather than embedded inline in a larger screen/form composable.

As per path instructions, "Dialogs must be separated into their own composables" and "Do not embed dialogs inline within complex main screens."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt`
around lines 167 - 188, The DatePickerDialog is embedded inline inside
LoanChargeOffForm, which violates the dialog separation guideline. Extract the
entire date-picker block into its own composable (for example, a dedicated
LoanChargeOffDatePickerDialog) and have LoanChargeOffForm call it when
state.showDatePicker is true. Keep the dialog’s current behavior by moving the
onDismissRequest, confirmButton, dismissButton, and DatePicker state handling
into the new composable, while preserving the existing LoanChargeOffAction
callbacks.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt`:
- Around line 228-232: The LoanChargeOff screen is formatting the transaction
date directly in the Composable, which violates the UI-layer formatting rule.
Move the `DateHelper.getDateAsStringFromLong` logic out of `LoanChargeOffScreen`
and into the ViewModel by adding a preformatted `transactionDateText` (or
similar) field on `LoanChargeOffState`, then update it whenever
`transactionDate` changes and bind `MifosDatePickerTextField` to that state
value instead.
- Around line 90-96: LoanChargeOffScreenContent currently violates the Screen
architecture by taking a NavController in addition to state and onAction. Move
the MifosBreadcrumbNavBar(navController) usage out of LoanChargeOffScreenContent
into LoanChargeOffScreen, or replace the navController dependency with a
narrowed composable slot/lambda so the Layer 2 composable only accepts state and
a single onAction callback. Keep the navigation reference confined to the entry
composable and update LoanChargeOffScreenContent’s signature accordingly.

In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt`:
- Around line 24-29: `LoanChargeOffScreen` should not depend on `NavController`;
keep that dependency in the route and use it only where `MifosBreadcrumbNavBar`
needs it. Update `LoanChargeOffScreenRoute` so the
`composable<LoanChargeOffRoute>` block still creates/passes navigation behavior,
but `LoanChargeOffScreen` receives only `state` and `onAction` (plus any other
UI-only params). Adjust the `LoanChargeOffScreen` signature and its callers
accordingly, and keep `navController` usage confined to the route-level
breadcrumb setup.

In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffViewModel.kt`:
- Around line 42-68: The async start-state updates in LoanChargeOffViewModel
bypass the reducer by calling mutableStateFlow.update directly inside
loadTemplate() and submitChargeOff(). Replace those direct mutations with new
Internal start actions (for example, TemplateLoadStarted and
ChargeOffSubmissionStarted) sent via sendAction(...), and handle them in
handleAction()/reducer alongside ReceiveTemplateResult and
ReceiveChargeOffResult so all state changes flow through one path.

---

Outside diff comments:
In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt`:
- Around line 391-395: The visible ChargeOff action is emitted by
LoanAccountActionViewModel but has no navigation target, so tapping it is a
no-op. Update LoanAccountActionNavigation to handle
LoanAccountActionItem.ChargeOff the same way the existing LoanChargeOff route is
handled, and ensure the ChargeOff action in LoanAccountActionItem is wired to
the actual charge-off destination instead of an empty block.

---

Nitpick comments:
In
`@core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt`:
- Around line 14-21: LoanChargeOffInput currently hardcodes the short date
pattern, so update the LoanChargeOffInput data class to reuse the shared
date-format constant instead of repeating the literal. Use the existing
DateHelper/DateConstants symbols already in the codebase, such as SHORT_MONTH or
a shared constant alongside DateConstants.DATE_FORMAT, and replace the default
dateFormat value in LoanChargeOffInput with that shared reference.

In
`@core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt`:
- Around line 118-128: The new getChargeOffTemplate and chargeOff additions in
DataManagerLoan are in a shared core module and should be treated as high-impact
changes. Update the surrounding module/documentation or PR notes to explicitly
call out that DataManagerLoan and its new loanService passthroughs affect
downstream consumers across the app, so they require extra review attention and
regression checking.

In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt`:
- Around line 167-188: The DatePickerDialog is embedded inline inside
LoanChargeOffForm, which violates the dialog separation guideline. Extract the
entire date-picker block into its own composable (for example, a dedicated
LoanChargeOffDatePickerDialog) and have LoanChargeOffForm call it when
state.showDatePicker is true. Keep the dialog’s current behavior by moving the
onDismissRequest, confirmButton, dismissButton, and DatePicker state handling
into the new composable, while preserving the existing LoanChargeOffAction
callbacks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 26f9ea92-0ff1-4d13-b884-ccfa706bf0a6

📥 Commits

Reviewing files that changed from the base of the PR and between 525e6d1 and da0d6ac.

📒 Files selected for processing (28)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanChargeOffInputMapper.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/LoanChargeOffRepository.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoanChargeOffRepositoryImpl.kt
  • core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/GetLoanChargeOffTemplateUseCase.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/LoanChargeOffUseCase.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/ChargeOffReasonOption.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.kt
  • core/ui/src/commonMain/composeResources/drawable/charge_off.xml
  • feature/loan/src/commonMain/composeResources/values/strings.xml
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/di/LoanModule.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffState.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffViewModel.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
  • GitHub Check: PR Checks / Build Desktop Application (macos-latest)
  • GitHub Check: PR Checks / Build Desktop Application (windows-latest)
  • GitHub Check: PR Checks / Build iOS App
  • GitHub Check: PR Checks / Build Web Application
  • GitHub Check: PR Checks / Build Android Application
🧰 Additional context used
📓 Path-based instructions (11)
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: Additional Code Review Guidelines:

  1. Null Safety & Stability
  • Avoid using !! operator
  • Handle null cases explicitly using safe calls or proper state handling
  • Do not assume values are always non-null without guarantees
  1. Architecture Boundaries
  • ViewModel must not depend on specific network/library implementations
  • Ensure proper separation between data, domain, and presentation layers
  • Do not format data (currency, dates, calculations) inside the UI layer
  • All formatting must be handled in the ViewModel and exposed via state (e.g., StateFlow)
  1. Performance Considerations
  • Avoid unnecessary recompositions in Compose
  • Do not attach heavy logic to frequently changing states (e.g., scrollState)
  • Prefer lifting state up instead of recomputing in child composables
  1. Compose & Navigation Best Practices
  • NEVER trigger navigation functions or side-effects directly during composition
  • Always wrap navigation calls inside LaunchedEffect or EventsEffect to avoid repeated execution on recomposition
  • Avoid triggering intensive side-effects during recomposition
  • Navigation routes must be type-safe.
  • Ensure all route classes or objects used for navigation are annotated with @Serializable.
  1. UI Structure
  • Dialogs must be separated into their own composables
  • Do not embed dialogs inline within complex main screens
  1. Localization Consistency
  • Ensure all supported languages are updated consistently across modules
  • Verify translations exist for newly added UI strings
  1. Code Cleanliness
  • Avoid unnecessary inline comments unless critical
  • Remove leftover debug or commented code
  1. Focus on correctness, readability, and maintainability over cosmetic nitpicks.
  • Avoid reviewing README, config, or asset files.
  • Prioritize identifying bugs, performance issues, and architectural concerns.
  1. Naming & Intent Rules:

Files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/di/LoanModule.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanChargeOffInputMapper.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffState.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/LoanChargeOffUseCase.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/ChargeOffReasonOption.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/GetLoanChargeOffTemplateUseCase.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/LoanChargeOffRepository.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoanChargeOffRepositoryImpl.kt
  • core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffViewModel.kt
**/data/mappers/**/*.kt

⚙️ CodeRabbit configuration file

**/data/mappers/**/*.kt: Mapper Consistency Rules (:core:data:mappers):

  • All mapping logic MUST be centralized in this directory.
  • Allowed mappings:
    1. DTO -> Domain Model
    2. Entity <-> Domain Model
  • Flag: Any mapper functions found in any module outside of :core:data:mappers.

Files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanChargeOffInputMapper.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.kt
**/{core-base,core}/**/*.kt

⚙️ CodeRabbit configuration file

**/{core-base,core}/**/*.kt: Critical Module Change Detection:

  • Changes in core-base module must be treated as high-impact.
  • Flag any PR that modifies files inside core-base for careful review.
  • Verify that modifications in core-base are necessary and minimal.
    Output:
  • Clearly highlight that core-base is a shared foundational module and requires extra review attention.

Files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanChargeOffInputMapper.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/LoanChargeOffUseCase.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/ChargeOffReasonOption.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/GetLoanChargeOffTemplateUseCase.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/LoanChargeOffRepository.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoanChargeOffRepositoryImpl.kt
  • core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt
**/network/**/*.kt

⚙️ CodeRabbit configuration file

**/network/**/*.kt: Network Layer API Guidelines:

  • One-shot API calls MUST use suspend, return raw response T, and MUST NOT use Flow or DataState.
  • Streaming APIs MUST return Flow<T> and MUST NOT use suspend or DataState.

Files:

  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt
**/network/dto/**/*.kt

⚙️ CodeRabbit configuration file

**/network/dto/**/*.kt: DTO Rules (:core:network:dto):

  • Classes here are Data Transfer Objects (DTOs) used strictly for API communication.
  • Rule: DTOs MUST NOT be used in ViewModels, Screens, or the Domain layer.
  • Flag: If a DTO is returned directly by a Repository interface or used in UI state.

Files:

  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt
**/core/model/**/*.kt

⚙️ CodeRabbit configuration file

**/core/model/**/*.kt: Domain Model Rules (:core:model):

  • Classes defined in this module are strictly Domain Models.
  • They must be plain Kotlin data classes.
  • They MUST NOT contain network-specific annotations (e.g., @Serializable) or database-specific annotations (e.g., @Entity).
  • Rule: These are the ONLY models that should be passed to or used within ViewModels and UI Screens.
  • Flag: If a Domain model is used directly as an API request/response body or a Room database table.

Files:

  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/ChargeOffReasonOption.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt
**/composeResources/values*/strings.xml

⚙️ CodeRabbit configuration file

**/composeResources/values*/strings.xml: String resource conventions:

Naming:

  • All keys must follow:
    feature_{feature_name}_{ui_text_in_snake_case}

Examples:
"In Advance" → feature_loan_in_advance
"Outstanding" → feature_loan_outstanding

  • Avoid generic names like: title, text1, label
  • The suffix should be a short, readable representation of the UI text
  • Avoid multiple keys representing the same UI text
  • Keys must be lowercase and use snake_case

Flag:

  • Incorrect naming pattern
  • Generic or unclear key names
  • Duplicate keys for same UI text

Files:

  • feature/loan/src/commonMain/composeResources/values/strings.xml
**/data/repository/**/*.kt

⚙️ CodeRabbit configuration file

**/data/repository/**/*.kt: Repository Interface Guidelines:

  • One-shot operations MUST use suspend fun and return DataState<T>. MUST NOT use Flow.
  • Streaming operations MUST return Flow<DataState<T>> and MUST NOT use suspend.
  • Repository interfaces must consistently return Domain models (from :core:model) wrapped in DataState or Flow.
  • Flag: Any interface method that returns a DTO or an Entity.

Files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/LoanChargeOffRepository.kt
**/*Screen.kt

⚙️ CodeRabbit configuration file

**/*Screen.kt: Screen architecture rules:

Each screen must follow a 2-layer structure:

  1. Layer 1 (Entry/Route Composable):

    • Function Name: Typically *ScreenRoute or the entry-point composable.
    • Responsibilities: Inject ViewModel (e.g., koinViewModel), take navigation lambdas, collect the StateFlow, and handle ViewModel events.
    • Logic: Should only handle ViewModel interaction, state collection, and triggering navigation in response to ViewModel events.
  2. Layer 2 (Stateful/Content Composable — *Screen or *ScreenContent):

    • Parameters: MUST only take state (the UI state object) and a single onAction lambda (e.g., onAction: (FeatureAction) -> Unit).
    • Responsibilities: Render the UI based strictly on the provided state.
    • Rule: MUST NOT pass multiple separate lambda functions for different UI interactions; consolidate them into the single onAction.
    • Constraint: Must NOT contain any business logic or ViewModel/Navigation references.

Internal/private helper composables (e.g., dialogs, sections, sub-components):

  • These are NOT subject to the single onAction rule.
  • They may accept specific, focused lambdas (e.g., onRetry: () -> Unit) or a narrowed onAction as appropriate.
  • However, they must NOT be passed the ViewModel or navigation controllers directly.

UI consistency:

  • Avoid hardcoded values (dp, sp, padding, fontSize, colors)
  • Use DesignToken, KptTheme, AppColors, MifosTypography for spacing, typography, and colors

Code quality:

  • Keep Composables small and readable
  • Avoid deeply nested UI

Flag:

  • Missing Layer 2 (*Screen/*ScreenContent) separation from the entry-point composable
  • Layer 2 (*Screen/*ScreenContent) receiving multiple separate lambdas instead of a single onAction
  • UI logic inside the entry-point composable
  • Business logic inside any Composable
  • Hardcoded strings instead of using string resources
  • Hardcoded dp/sp values
  • Direct styling instead of using DesignToken or KptTheme

Files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileScreen.kt
**/data/repositoryImp/**/*.kt

⚙️ CodeRabbit configuration file

**/data/repositoryImp/**/*.kt: Repository Implementation Guidelines:

  • MUST convert T -> DataState<T> for one-shot APIs, and Flow<T> -> Flow<DataState<T>> using .asDataStateFlow().
  • MUST perform network availability checks, handle exceptions, and apply appropriate dispatchers.
  • Repositories act as the boundary translator. They MUST use mappers to convert DTOs (from network) and Entities (from database) into Domain Models (from :core:model) before returning data.
  • Flag: If a repository implementation returns a raw DTO or Entity directly to the caller instead of a Domain model.

Files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoanChargeOffRepositoryImpl.kt
**/*ViewModel.kt

⚙️ CodeRabbit configuration file

**/*ViewModel.kt: MVI architecture rules:

  • All new features must follow MVI
  • ViewModel must extend BaseViewModel
  • The ViewModel MUST maintain a single UI state (e.g., a single StateFlow)
    instead of multiple separate state variables.

Required:

  • Use *State, *Event, *Action
  • Naming must be consistent (FeatureViewModel, FeatureState, FeatureEvent, FeatureAction)
  • Follow unidirectional flow:
    Action → ViewModel → State → UI

Internal reducer/action architecture rules:

  • Async operations MUST NOT directly mutate UI state repeatedly inside
    Flow collectors, suspend callbacks, or repository result handlers.

  • Repository/network/database results MUST be converted into internal
    actions using sendAction(...).

  • handleAction(...) must act as the primary reducer responsible for:

    • state mutation
    • reducer-style state transitions
    • triggering follow-up actions
  • Large async methods must be split into:

    1. async collection layer
    2. internal action dispatching
    3. reducer/state handling
  • Avoid directly calling another business/data-loading method from
    repository collectors or async callbacks.
    Prefer dispatching follow-up internal actions instead.

Preferred pattern:
repository result
-> sendAction(...)
-> handleAction(...)
-> mutableStateFlow.update { ... }

Anti-pattern examples:
mutableStateFlow.update { ... } inside collect { }
fetchX() -> directly calls fetchY() inside async collector
large methods mixing:
- collection
- state mutation
- navigation
- business chaining

Flag:

  • Multiple mutableStateFlow.update {} calls inside collect { }
  • Direct state mutation inside async repository callbacks
  • Async methods performing both collection and reducer logic
  • Direct business-flow chaining from async collectors
  • Missing internal reducer actions for async results
  • Missing *State / *Event / *Action
  • ViewModel not...

Files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffViewModel.kt
🧠 Learnings (4)
📚 Learning: 2026-02-06T13:15:16.968Z
Learnt from: sahilshivekar
Repo: openMF/android-client PR: 2603
File: feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanTransaction/LoanTransactionsViewModel.kt:43-106
Timestamp: 2026-02-06T13:15:16.968Z
Learning: Guideline: When a Kotlin function parameter is nullable (e.g., balance: Double?, currencyCode: String?, maximumFractionDigits: Int?) and downstream calls require a non-null value, add null-safety handling in all implementations. Specifically, avoid calling Currency.getInstance(currencyCode) with a possibly null currencyCode; provide a safe default (e.g., currencyCode ?: "$") or validate before use. Ensure all platform targets (Android/Desktop/Native) follow consistent null handling, and consider centralizing currencyCode normalization in the common layer if feasible. Add tests covering null currencyCode to prevent NPEs.

Applied to files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/di/LoanModule.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanChargeOffInputMapper.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffState.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/LoanChargeOffUseCase.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/ChargeOffReasonOption.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/GetLoanChargeOffTemplateUseCase.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/LoanChargeOffRepository.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoanChargeOffRepositoryImpl.kt
  • core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffViewModel.kt
📚 Learning: 2026-04-01T05:03:14.323Z
Learnt from: kartikey004
Repo: openMF/mifos-x-field-officer-app PR: 2659
File: feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanDisbursement/LoanAccountDisbursementScreen.kt:190-195
Timestamp: 2026-04-01T05:03:14.323Z
Learning: In this repo, existing `SelectableDates` / `SelectableDates.isSelectableDate(utcTimeMillis: Long)` implementations use `Clock.System.now().toEpochMilliseconds()` (UTC epoch millis) for date-boundary checks. During PR reviews, do not flag these checks for not using a timezone-aware `LocalDate` start-of-day approach; treat it as an established project-wide pattern. If a change is desired, handle it as a coordinated project-wide improvement rather than as a per-PR review issue.

Applied to files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/di/LoanModule.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanChargeOffInputMapper.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffState.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/LoanChargeOffUseCase.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/ChargeOffReasonOption.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/GetLoanChargeOffTemplateUseCase.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/LoanChargeOffRepository.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoanChargeOffRepositoryImpl.kt
  • core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffViewModel.kt
📚 Learning: 2026-03-16T11:58:32.496Z
Learnt from: sahilshivekar
Repo: openMF/mifos-x-field-officer-app PR: 2647
File: feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt:96-96
Timestamp: 2026-03-16T11:58:32.496Z
Learning: In feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt (Kotlin/Compose Multiplatform), navigateToDashboard uses a direct method reference navController::navigateToLoanDashboardScreen without an ID guard. This is intentional: LoanAccountProfileScreen always provides a valid loanId, and LoanDashboardScreen handles invalid/missing data by showing a 'Failed to fetch Loan details' error state. Do not flag the absence of an ID guard here in future reviews.

Applied to files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt
📚 Learning: 2026-02-16T08:26:18.398Z
Learnt from: kartikey004
Repo: openMF/android-client PR: 2610
File: core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/theme/DesignToken.kt:328-337
Timestamp: 2026-02-16T08:26:18.398Z
Learning: In core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/theme/DesignToken.kt, ensure size tokens in AppSizes use raw dp-based names like dp5, dp18, dp20, dp42, dp48, dp72, dp100, dp120, dp128, etc., rather than relying solely on semantic names. This naming convention should be accepted for design token definitions in this file and should guide future token definitions without requiring semantic aliases.

Applied to files:

  • core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt
🔇 Additional comments (27)
core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/ChargeOffReasonOption.kt (1)

12-19: LGTM!

core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt (1)

14-22: LGTM!

core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt (1)

14-29: LGTM!

core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt (1)

14-27: LGTM!

core/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.kt (1)

26-28: LGTM!

Also applies to: 79-89

core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt (1)

48-48: LGTM!

Also applies to: 118-118, 202-202

core/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.kt (1)

92-93: LGTM!

Also applies to: 178-179

core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt (2)

26-28: LGTM!

Also applies to: 118-128


389-391: LGTM!

Also applies to: 409-411

core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.kt (1)

15-22: LGTM!

core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanChargeOffInputMapper.kt (1)

15-22: LGTM!

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

16-21: LGTM!

Both methods are suspend fun returning DataState<T> with no Flow in sight — right in line with LoanChargeOffRepository.kt's one-shot repository contract. As per path instructions, "One-shot operations MUST use suspend fun and return DataState<T>. MUST NOT use Flow."

Source: Path instructions

core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoanChargeOffRepositoryImpl.kt (1)

28-47: LGTM!

Nice boundary translation here — LoanChargeOffRepositoryImpl.kt wraps calls in runAsDataState with networkMonitor/dispatcher.io, and maps DTOs to domain models (toModel()) before returning — right in line with "Repositories act as the boundary translator. They MUST use mappers to convert DTOs... into Domain Models before returning data." Confirmed via Kotlin's spec-defined Unit-coercion that the chargeOff block returning a discarded LoanChargeOffResponseDto against a declared DataState<Unit> compiles cleanly — no type mismatch here.

Source: Path instructions

core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/GetLoanChargeOffTemplateUseCase.kt (1)

16-22: LGTM!

core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/LoanChargeOffUseCase.kt (1)

16-23: LGTM!

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffState.kt (1)

17-35: LGTM!

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffViewModel.kt (1)

70-163: LGTM!

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt (1)

68-88: LGTM!

core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt (1)

50-50: LGTM!

Note: this touches a shared core module file; as per path instructions, changes under **/{core-base,core}/**/*.kt should get extra scrutiny, but this is a minimal, additive icon mapping with no behavior change elsewhere.

Also applies to: 269-269

Source: Path instructions

core/ui/src/commonMain/composeResources/drawable/charge_off.xml (1)

15-16: 🩺 Stability & Availability | ⚡ Quick win

android:tint="?attr/colorControlNormal" is unsupported in Compose Multiplatform resources.

This drawable lives under commonMain/composeResources/drawable, so it's compiled for all KMP targets, not just Android. Official Kotlin Multiplatform docs instruct to "Remove any other Android-specific attributes for color adjustments like android:tint." when adding vector icons to multiplatform resources, since theme-attribute references (?attr/...) have no equivalent outside the Android theme system.

🔧 Suggested fix
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
     android:viewportWidth="960"
-    android:viewportHeight="960"
-    android:tint="?attr/colorControlNormal">
+    android:viewportHeight="960">
   <path
       android:fillColor="`#e3e3e3`"
       android:pathData="..."/>
 </vector>

Apply tinting at the Compose call site (e.g., via Icon's tint parameter or ColorFilter) instead of the XML attribute.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileNavigation.kt (1)

39-42: LGTM!

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileScreen.kt (1)

78-95: LGTM!

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt (1)

23-27: LGTM on the wiring itself — flagged the underlying duplicate-action-item concern separately in LoanAccountActionItem.kt.

Also applies to: 82-82

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

167-182: LGTM!

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt (1)

17-18: LGTM!

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/di/LoanModule.kt (1)

22-22: LGTM!

Also applies to: 39-39

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt (1)

31-32: LGTM!

Also applies to: 90-93, 125-125

@revanthkumarJ

Copy link
Copy Markdown
Contributor

@sahilshivekar upload video or screenshots

@revanthkumarJ The app isn't working now. Server is responding with status code 502

ask victor once in slack and let me know once its working and screenshots or video is attached with this pr

@sahilshivekar

Copy link
Copy Markdown
Contributor Author

@sahilshivekar upload video or screenshots

@revanthkumarJ The app isn't working now. Server is responding with status code 502

ask victor once in slack and let me know once its working and screenshots or video is attached with this pr

@revanthkumarJ I did that already, he isn't active

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt (1)

150-171: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract DatePickerDialog into its own composable.

The date-picker dialog is embedded inline inside LoanChargeOffForm. Per path instructions, dialogs must be separated into their own composables rather than embedded inline within complex screens (the LoanChargeOffDialog at Line 238 already follows this pattern correctly).

♻️ Suggested extraction
+@Composable
+private fun LoanChargeOffDatePickerDialog(
+    dueDatePickerState: DatePickerState,
+    onConfirm: (Long) -> Unit,
+    onDismiss: () -> Unit,
+) {
+    DatePickerDialog(
+        onDismissRequest = onDismiss,
+        confirmButton = {
+            TextButton(
+                onClick = {
+                    dueDatePickerState.selectedDateMillis?.let(onConfirm)
+                    onDismiss()
+                },
+            ) { Text(stringResource(Res.string.ok)) }
+        },
+        dismissButton = {
+            TextButton(onClick = onDismiss) { Text(stringResource(Res.string.cancel)) }
+        },
+    ) {
+        DatePicker(state = dueDatePickerState)
+    }
+}

Then call it conditionally from LoanChargeOffForm when state.showDatePicker is true.

As per path instructions, "Dialogs must be separated into their own composables" and "Do not embed dialogs inline within complex main screens."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt`
around lines 150 - 171, The inline DatePickerDialog inside LoanChargeOffForm
should be extracted into a dedicated composable, matching the existing
LoanChargeOffDialog pattern. Move the dialog UI and its confirm/dismiss handling
into a new composable (for example, a DatePickerDialog wrapper) and have
LoanChargeOffForm conditionally invoke that composable when state.showDatePicker
is true. Keep the action wiring through
LoanChargeOffAction.TransactionDateChanged and
LoanChargeOffAction.HideDatePicker unchanged, but relocate the dialog-specific
code out of the main screen composable.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt`:
- Around line 150-171: The inline DatePickerDialog inside LoanChargeOffForm
should be extracted into a dedicated composable, matching the existing
LoanChargeOffDialog pattern. Move the dialog UI and its confirm/dismiss handling
into a new composable (for example, a DatePickerDialog wrapper) and have
LoanChargeOffForm conditionally invoke that composable when state.showDatePicker
is true. Keep the action wiring through
LoanChargeOffAction.TransactionDateChanged and
LoanChargeOffAction.HideDatePicker unchanged, but relocate the dialog-specific
code out of the main screen composable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 67b8ca79-070e-4b54-b629-4ddf34359663

📥 Commits

Reviewing files that changed from the base of the PR and between 487bb4f and c25c091.

📒 Files selected for processing (30)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanChargeOffInputMapper.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/LoanChargeOffRepository.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoanChargeOffRepositoryImpl.kt
  • core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/GetLoanChargeOffTemplateUseCase.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/LoanChargeOffUseCase.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/ChargeOffReasonOption.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.kt
  • core/ui/src/commonMain/composeResources/drawable/charge_off.xml
  • feature/loan/src/commonMain/composeResources/values/strings.xml
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/di/LoanModule.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/payments/LoanActionPaymentsScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffState.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffViewModel.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt
✅ Files skipped from review due to trivial changes (4)
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/ChargeOffReasonOption.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileNavigation.kt
  • feature/loan/src/commonMain/composeResources/values/strings.xml
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffTemplateDto.kt
🚧 Files skipped from review as they are similar to previous changes (20)
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/GetLoanChargeOffTemplateUseCase.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffRequestDto.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/LoanChargeOffUseCase.kt
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/LoanChargeOffInput.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoanChargeOffRepositoryImpl.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/di/LoanModule.kt
  • core/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/LoanChargeOffResponseDto.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/LoanChargeOffRepository.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt
  • core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt
  • core/ui/src/commonMain/composeResources/drawable/charge_off.xml
  • core/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.kt
  • core/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanChargeOffInputMapper.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffState.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffViewModel.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.kt
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: PR Checks / Static Analysis Check
🧰 Additional context used
📓 Path-based instructions (2)
**/*Screen.kt

⚙️ CodeRabbit configuration file

**/*Screen.kt: Screen architecture rules:

Each screen must follow a 2-layer structure:

  1. Layer 1 (Entry/Route Composable):

    • Function Name: Typically *ScreenRoute or the entry-point composable.
    • Responsibilities: Inject ViewModel (e.g., koinViewModel), take navigation lambdas, collect the StateFlow, and handle ViewModel events.
    • Logic: Should only handle ViewModel interaction, state collection, and triggering navigation in response to ViewModel events.
  2. Layer 2 (Stateful/Content Composable — *Screen or *ScreenContent):

    • Parameters: MUST only take state (the UI state object) and a single onAction lambda (e.g., onAction: (FeatureAction) -> Unit).
    • Responsibilities: Render the UI based strictly on the provided state.
    • Rule: MUST NOT pass multiple separate lambda functions for different UI interactions; consolidate them into the single onAction.
    • Constraint: Must NOT contain any business logic or ViewModel/Navigation references.

Internal/private helper composables (e.g., dialogs, sections, sub-components):

  • These are NOT subject to the single onAction rule.
  • They may accept specific, focused lambdas (e.g., onRetry: () -> Unit) or a narrowed onAction as appropriate.
  • However, they must NOT be passed the ViewModel or navigation controllers directly.

UI consistency:

  • Avoid hardcoded values (dp, sp, padding, fontSize, colors)
  • Use DesignToken, KptTheme, AppColors, MifosTypography for spacing, typography, and colors

Code quality:

  • Keep Composables small and readable
  • Avoid deeply nested UI

Flag:

  • Missing Layer 2 (*Screen/*ScreenContent) separation from the entry-point composable
  • Layer 2 (*Screen/*ScreenContent) receiving multiple separate lambdas instead of a single onAction
  • UI logic inside the entry-point composable
  • Business logic inside any Composable
  • Hardcoded strings instead of using string resources
  • Hardcoded dp/sp values
  • Direct styling instead of using DesignToken or KptTheme

Files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/payments/LoanActionPaymentsScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: Additional Code Review Guidelines:

  1. Null Safety & Stability
  • Avoid using !! operator
  • Handle null cases explicitly using safe calls or proper state handling
  • Do not assume values are always non-null without guarantees
  1. Architecture Boundaries
  • ViewModel must not depend on specific network/library implementations
  • Ensure proper separation between data, domain, and presentation layers
  • Do not format data (currency, dates, calculations) inside the UI layer
  • All formatting must be handled in the ViewModel and exposed via state (e.g., StateFlow)
  1. Performance Considerations
  • Avoid unnecessary recompositions in Compose
  • Do not attach heavy logic to frequently changing states (e.g., scrollState)
  • Prefer lifting state up instead of recomputing in child composables
  1. Compose & Navigation Best Practices
  • NEVER trigger navigation functions or side-effects directly during composition
  • Always wrap navigation calls inside LaunchedEffect or EventsEffect to avoid repeated execution on recomposition
  • Avoid triggering intensive side-effects during recomposition
  • Navigation routes must be type-safe.
  • Ensure all route classes or objects used for navigation are annotated with @Serializable.
  1. UI Structure
  • Dialogs must be separated into their own composables
  • Do not embed dialogs inline within complex main screens
  1. Localization Consistency
  • Ensure all supported languages are updated consistently across modules
  • Verify translations exist for newly added UI strings
  1. Code Cleanliness
  • Avoid unnecessary inline comments unless critical
  • Remove leftover debug or commented code
  1. Focus on correctness, readability, and maintainability over cosmetic nitpicks.
  • Avoid reviewing README, config, or asset files.
  • Prioritize identifying bugs, performance issues, and architectural concerns.
  1. Naming & Intent Rules:

Files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/payments/LoanActionPaymentsScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt
🧠 Learnings (2)
📚 Learning: 2026-02-06T13:15:16.968Z
Learnt from: sahilshivekar
Repo: openMF/android-client PR: 2603
File: feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanTransaction/LoanTransactionsViewModel.kt:43-106
Timestamp: 2026-02-06T13:15:16.968Z
Learning: Guideline: When a Kotlin function parameter is nullable (e.g., balance: Double?, currencyCode: String?, maximumFractionDigits: Int?) and downstream calls require a non-null value, add null-safety handling in all implementations. Specifically, avoid calling Currency.getInstance(currencyCode) with a possibly null currencyCode; provide a safe default (e.g., currencyCode ?: "$") or validate before use. Ensure all platform targets (Android/Desktop/Native) follow consistent null handling, and consider centralizing currencyCode normalization in the common layer if feasible. Add tests covering null currencyCode to prevent NPEs.

Applied to files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/payments/LoanActionPaymentsScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt
📚 Learning: 2026-04-01T05:03:14.323Z
Learnt from: kartikey004
Repo: openMF/mifos-x-field-officer-app PR: 2659
File: feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanDisbursement/LoanAccountDisbursementScreen.kt:190-195
Timestamp: 2026-04-01T05:03:14.323Z
Learning: In this repo, existing `SelectableDates` / `SelectableDates.isSelectableDate(utcTimeMillis: Long)` implementations use `Clock.System.now().toEpochMilliseconds()` (UTC epoch millis) for date-boundary checks. During PR reviews, do not flag these checks for not using a timezone-aware `LocalDate` start-of-day approach; treat it as an established project-wide pattern. If a change is desired, handle it as a coordinated project-wide improvement rather than as a per-PR review issue.

Applied to files:

  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/payments/LoanActionPaymentsScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt
🔇 Additional comments (8)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreen.kt (3)

65-126: LGTM!


172-236: LGTM! Form fields correctly source formatted date text (state.transactionDateText) from state rather than formatting in the UI layer, and use design tokens for spacing.


238-251: LGTM! Dialog correctly isolated into its own composable, driven by state.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanChargeOff/LoanChargeOffScreenRoute.kt (1)

1-35: LGTM! Route is properly @Serializable, and the past concern about passing navController into LoanChargeOffScreen is resolved — only onNavigateBack/onChargeOffSuccess are passed now.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionItem.kt (1)

156-489: LGTM! id field addition is consistent across all action entries and each id appears unique, enabling the key = { it.id } fix used downstream.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.kt (1)

22-101: LGTM! navigateToChargeOff wiring and the new reloadLoanAccountActionScreen (pop-up-to + launchSingleTop) look correct for refreshing the action list post charge-off.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionScreen.kt (1)

113-117: LGTM! Using it.id as the stable list key is a solid improvement over it.title.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/payments/LoanActionPaymentsScreen.kt (1)

92-94: LGTM! Consistent with the same it.id key fix applied in LoanAccountActionScreen.kt.

@sahilshivekar sahilshivekar changed the title feat(loan): Implement Loan Charge-Off Screen feat(loan): implement loan charge-off screen Jul 2, 2026

@revanthkumarJ revanthkumarJ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

while you called api show a overlay loader @sahilshivekar

@sonarqubecloud

sonarqubecloud Bot commented Jul 2, 2026

Copy link
Copy Markdown

@sahilshivekar

Copy link
Copy Markdown
Contributor Author

while you called api show a overlay loader @sahilshivekar

@revanthkumarJ Done now

@revanthkumarJ revanthkumarJ merged commit 928fc44 into openMF:dev Jul 2, 2026
10 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