feat(loan): implement assign loan officer screen - #2699
Conversation
|
Warning Review limit reached
Next review available in: 4 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughAdds an end-to-end Assign Loan Officer flow across network, data, domain, and Compose feature layers. It also reorganizes loan repository and template DTO packages and updates dependent imports and model types. ChangesLoan officer assignment backend and domain View backend and domain checkpoints
Assign Loan Officer feature View feature checkpoints
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)Assignment flowsequenceDiagram
participant LoanAccountAction
participant LoanNavigation
participant AssignLoanOfficerScreen
participant AssignLoanOfficerViewModel
participant AssignLoanOfficerUseCase
LoanAccountAction->>LoanNavigation: open assignment route
LoanNavigation->>AssignLoanOfficerScreen: provide loanId
AssignLoanOfficerScreen->>AssignLoanOfficerViewModel: load options and submit actions
AssignLoanOfficerViewModel->>AssignLoanOfficerUseCase: invoke assignment
AssignLoanOfficerUseCase-->>AssignLoanOfficerViewModel: return assignment result
Possibly related PRs Related pull requests
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/assignLoanOfficer/AssignLoanOfficerInput.kt (1)
17-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePrefer
nullas the default for optional identifiers.Since
fromLoanOfficerIdis typed as a nullable string (String?), it is typically safer and more semantically correct to default tonullrather than an empty string"". An empty string sent over the network could be interpreted incorrectly if the backend strictly expects either a valid string identifier or a null value.💡 Proposed fix for the default value
- val fromLoanOfficerId: String? = "", + val fromLoanOfficerId: String? = null,🤖 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/assignLoanOfficer/AssignLoanOfficerInput.kt` at line 17, Update the fromLoanOfficerId property in AssignLoanOfficerInput to default to null instead of an empty string, preserving its nullable String type and ensuring omitted optional identifiers remain null.core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt (1)
208-208: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueCritical module change detection.
Please note that
core-base(and thecorelayer) is a shared foundational module and requires extra review attention. Ensure that all modifications in RepositoryModule.kt are necessary and minimal as per path instructions. The DI additions here appear safe and well-contained.🤖 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/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt` at line 208, Keep the LoanOfficerRepositoryImpl binding in RepositoryModule.kt minimal and limited to the required singleOf declaration with LoanOfficerRepository::class. Avoid unrelated changes to this shared foundational DI module.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/assignLoanOfficer/AssignLoanOfficerScreen.kt`:
- Around line 58-107: Split AssignLoanOfficerScreen into a Layer 1 route that
retains ViewModel injection, state collection, event handling, navigation, and
dialog wiring, and a separate Layer 2 content composable that receives only the
collected state and an onAction callback. Move the MifosScaffold and viewState
rendering logic, including AssignLoanOfficerForm, into the content composable,
and have AssignLoanOfficerScreen delegate to it.
- Line 173: Move loan officer label resolution out of the composable’s options
mapping and into the ViewModel/state that supplies the officers, exposing a
precomputed non-null display label for each LoanOfficerOption. Update the
state-producing logic to prefer displayName and safely fall back to available
firstname/lastname values without producing “null null”, then have
AssignLoanOfficerScreen reuse that state label directly.
In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/assignLoanOfficer/AssignLoanOfficerViewModel.kt`:
- Around line 196-209: Remove the file-level cached defaultAssignmentDate and
compute the current timestamp when each AssignLoanOfficerState is constructed,
using that same per-instance value for both assignmentDateMillis and
assignmentDateText. Preserve the existing date formatting behavior and avoid
sharing a timestamp across view-model instances.
---
Nitpick comments:
In `@core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt`:
- Line 208: Keep the LoanOfficerRepositoryImpl binding in RepositoryModule.kt
minimal and limited to the required singleOf declaration with
LoanOfficerRepository::class. Avoid unrelated changes to this shared
foundational DI module.
In
`@core/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/assignLoanOfficer/AssignLoanOfficerInput.kt`:
- Line 17: Update the fromLoanOfficerId property in AssignLoanOfficerInput to
default to null instead of an empty string, preserving its nullable String type
and ensuring omitted optional identifiers remain null.
🪄 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: 0a4f57d1-af21-4dc9-a7da-cc5b89ae9502
📒 Files selected for processing (76)
core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/ChargeOffReasonOptionMapper.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/GuarantorMapper.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/mappers/loan/LoanOfficerMapper.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanAccountApprovalRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanAccountDisbursementRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanAccountRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanAccountSummaryRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanChargeFormRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanChargeOffRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanChargeRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanCreateGuarantorRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanOfficerRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanRepaymentRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanRepaymentScheduleRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanReschedulesRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repository/loan/LoanTransactionsRepository.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanAccountApprovalRepositoryImp.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanAccountDisbursementRepositoryImp.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanAccountRepositoryImp.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanAccountSummaryRepositoryImp.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanChargeFormRepositoryImp.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanChargeOffRepositoryImpl.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanChargeRepositoryImp.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanCreateGuarantorRepositoryImp.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanOfficerRepositoryImpl.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanRepaymentRepositoryImp.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanRepaymentScheduleRepositoryImp.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanReschedulesRepositoryImpl.ktcore/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/loan/LoanTransactionsRepositoryImp.ktcore/database/src/commonMain/kotlin/com/mifos/room/entities/templates/loans/LoanTemplate.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/CalculateLoanScheduleUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/CreateLoanAccountUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/CreateLoanChargesUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/GetAllLoanUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/GetChargeTemplateUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/GetListOfLoanChargesUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/GetLoansAccountTemplateUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/assignLoanOfficer/AssignLoanOfficerUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/assignLoanOfficer/GetLoanOfficerOptionsUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/createGuarantor/CreateGuarantorUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/createGuarantor/GetGuarantorAccountTemplateUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/createGuarantor/GetGuarantorTemplateUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/GetLoanChargeOffTemplateUseCase.ktcore/domain/src/commonMain/kotlin/com/mifos/core/domain/useCases/loanChargeOff/LoanChargeOffUseCase.ktcore/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/assignLoanOfficer/AssignLoanOfficerInput.ktcore/model/src/commonMain/kotlin/com/mifos/core/model/objects/account/loan/assignLoanOfficer/AssignLoanOfficerResponse.ktcore/model/src/commonMain/kotlin/com/mifos/core/model/objects/template/loan/GroupLoanTemplate.ktcore/model/src/commonMain/kotlin/com/mifos/core/model/objects/template/loan/LoanOfficerOption.ktcore/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerLoan.ktcore/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/assignLoanOfficer/AssignLoanOfficerRequestDto.ktcore/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/assignLoanOfficer/AssignLoanOfficerResponseDto.ktcore/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/template/GuarantorTemplateDto.ktcore/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/template/LoanChargeOffTemplateDto.ktcore/network/src/commonMain/kotlin/com/mifos/core/network/dto/loans/template/LoanOfficerOptionsTemplateDto.ktcore/network/src/commonMain/kotlin/com/mifos/core/network/services/LoanService.ktfeature/loan/src/commonMain/composeResources/values/strings.xmlfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/amountTransfer/AmountTransferViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/assignLoanOfficer/AssignLoanOfficerRoute.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/assignLoanOfficer/AssignLoanOfficerScreen.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/assignLoanOfficer/AssignLoanOfficerViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/createLoanReschedules/LoanRescheduleFormViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/di/LoanModule.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionNavigation.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountAction/LoanAccountActionViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountProfile/LoanAccountProfileViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanAccountSummary/LoanAccountSummaryViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanApproval/LoanAccountApprovalViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanDashboard/LoanDashboardViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanDisbursement/LoanAccountDisbursementViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanRepayment/LoanRepaymentViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanRepaymentSchedule/LoanRepaymentScheduleViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanReschedules/LoanReschedulesViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanTransaction/LoanTransactionsViewModel.ktfeature/loan/src/commonMain/kotlin/com/mifos/feature/loan/navigation/LoanNavigation.kt
|



Fixes - Jira-#680
Before (Clicking on assign loan officer doesn't make changes in state)
After
assign_loan_officer.mp4