Skip to content

feat: Create Client and Loan Application in One Shot - #2623

Merged
therajanmaurya merged 14 commits into
openMF:developmentfrom
itsPronay:client-loan-account-flow
Mar 3, 2026
Merged

feat: Create Client and Loan Application in One Shot#2623
therajanmaurya merged 14 commits into
openMF:developmentfrom
itsPronay:client-loan-account-flow

Conversation

@itsPronay

@itsPronay itsPronay commented Feb 23, 2026

Copy link
Copy Markdown
Member

Fixes - https://mifosforge.jira.com/browse/MIFOSAC-707

Before After
https://github.com/user-attachments/assets/0b49daf9-bff5-4e66-9edd-b1f5195fd82a https://github.com/user-attachments/assets/8d606c23-1739-46f6-be3d-7b24afc2079c

Summary by CodeRabbit

  • Refactor
    • Simplified navigation routing logic for improved consistency.
    • Enhanced client creation workflow with improved navigation handling.
    • Added processing delay to client creation flow for better user experience.

@coderabbitai

coderabbitai Bot commented Feb 23, 2026

Copy link
Copy Markdown

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
📝 Walkthrough

Walkthrough

The changes refactor the client creation flow by renaming CreateNewClientScreen to CreateNewClientScreenRoute, adding a navigateToClientDetails callback parameter, modifying the OnImageUploadSuccess state to carry clientId, introducing a 1-second delay after client creation, and updating navigation routing to thread the new parameter through the stack.

Changes

Cohort / File(s) Summary
Client Creation Screen Refactoring
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt
Renamed composable entry point to CreateNewClientScreenRoute, added navigateToClientDetails parameter, removed initial LaunchedEffect for office/template loading, and changed navigation behavior to invoke navigateToClientDetails(uiState.id) on successful client creation instead of navigateBack.
Client State Management
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientUiState.kt, feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt
Updated OnImageUploadSuccess to include clientId field; added initialization hook in ViewModel to load office/template on creation; inserted 1-second delay after successful client creation before emitting client ID; extended loadStaffInOffices to handle DataState.Loading state.
Client Navigation Routing
feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt, cmp-navigation/src/commonMain/kotlin/cmp/navigation/authenticated/AuthenticatedNavbarNavigationScreen.kt
Updated createClientRoute signature to accept navigateToClientDetails callback and wired it to navController::navigateToClientDetailsProfileRoute; simplified search navigation from lambda wrapper to direct function reference in navbar screen.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • itsPronay
  • biplab1
  • TheKalpeshPawar

Poem

🐰 A journey for clients, now cleaner and bright,
Through renamed screens and callbacks just right,
With IDs in tow and delays to respect,
Our navigation flows now perfectly connect! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: enabling client and loan application creation in a single flow, which is reflected across all file changes including navigation routing, UI state management, and view model logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 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.

@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: 3

Caution

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

⚠️ Outside diff range comments (4)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt (2)

233-239: ⚠️ Potential issue | 🔴 Critical

Navigation called as a side effect during composition — will fire on every recomposition.

navigateToCreateLoanAccount(uiState.id) is called directly inside the when branch, which executes during composition. Since SetClientId persists in the StateFlow, any recomposition (rotation, returning from the loan screen) will re-trigger navigation, potentially pushing duplicate screens onto the back stack.

Wrap this in a LaunchedEffect keyed on the state to ensure it fires only once:

🐛 Proposed fix
             is CreateNewClientUiState.SetClientId -> {
                 if (createClientWithImage) {
                     uploadImage(uiState.id)
                 } else {
-                    navigateToCreateLoanAccount(uiState.id)
+                    LaunchedEffect(uiState) {
+                        navigateToCreateLoanAccount(uiState.id)
+                    }
                 }
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`
around lines 233 - 239, The navigation call is happening during composition in
CreateNewClientScreen: when handling CreateNewClientUiState.SetClientId the code
calls navigateToCreateLoanAccount(uiState.id) (or uploadImage(uiState.id))
directly which will re-fire on every recomposition; wrap the side-effectful
calls in a LaunchedEffect keyed on the unique id (e.g., uiState.id) or the state
to ensure the action runs only once per new id—move the
navigateToCreateLoanAccount(uiState.id) and uploadImage(uiState.id) calls into
that LaunchedEffect block so composition no longer triggers navigation/upload
repeatedly.

250-258: ⚠️ Potential issue | 🔴 Critical

Same recomposition-safety issue: navigation + snackbar launched during composition.

Both scope.launch { snackbar } and navigateToCreateLoanAccount(uiState.clientId) are side effects that run on every recomposition. This will show duplicate snackbars and fire duplicate navigations.

🐛 Proposed fix
             is CreateNewClientUiState.OnImageUploadSuccess -> {
-                scope.launch {
-                    snackbarHostState.showSnackbar(
-                        message = getString(Res.string.feature_client_Image_Upload_Successful),
-                        duration = SnackbarDuration.Long,
-                    )
+                LaunchedEffect(uiState) {
+                    snackbarHostState.showSnackbar(
+                        message = getString(Res.string.feature_client_Image_Upload_Successful),
+                        duration = SnackbarDuration.Long,
+                    )
+                    navigateToCreateLoanAccount(uiState.clientId)
                 }
-                navigateToCreateLoanAccount(uiState.clientId)
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`
around lines 250 - 258, The code is launching a snackbar and calling
navigateToCreateLoanAccount during composition for
CreateNewClientUiState.OnImageUploadSuccess which causes duplicate side-effects
on recomposition; wrap the side-effects in a Compose side-effect such as
LaunchedEffect keyed to the success event (e.g., LaunchedEffect(uiState) or
LaunchedEffect(uiState.clientId) and check uiState is
CreateNewClientUiState.OnImageUploadSuccess inside it), then call
snackbarHostState.showSnackbar(...) and
navigateToCreateLoanAccount(uiState.clientId) from within that LaunchedEffect so
both the snackbarHostState.showSnackbar and navigateToCreateLoanAccount are
executed exactly once when the success state appears instead of on every
recomposition.
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt (2)

155-160: ⚠️ Potential issue | 🟠 Major

Hardcoded delay(1000) is fragile and has side effects on recomposition.

Issues with this approach:

  1. On configuration change or process death, StateFlow replays the last emitted value (SetClientId), which will re-trigger navigation.
  2. The 1000ms is arbitrary and races against snackbar display duration — on slow devices the snackbar may not even render before navigation fires.
  3. If the coroutine scope is cancelled during the delay (e.g., navigating away), the SetClientId emission is silently lost.

Consider using a one-time navigation event (e.g., a Channel / SharedFlow with replay=0) instead of encoding navigation triggers in the StateFlow state, or at minimum let the UI drive the timing (e.g., navigate after snackbar is dismissed).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt`
around lines 155 - 160, The current use of delay(1000) between setting
_createNewClientUiState to CreateNewClientUiState.ShowClientCreatedSuccessfully
and then emitting CreateNewClientUiState.SetClientId is fragile: it races with
snackbar display, is cancelled silently, and StateFlow replay will re-trigger
navigation on restore. Replace this pattern with a one-time event channel or
shared flow (e.g., a Channel or MutableSharedFlow(replay = 0)) for navigation
events, emitting the client id into that one-time stream instead of encoding it
in _createNewClientUiState; alternatively, let the UI call a ViewModel method
(e.g., onSnackbarDismissed) to trigger emitting SetClientId so the UI drives the
timing rather than a fixed delay.

165-167: ⚠️ Potential issue | 🟠 Major

Missing UI state update in catch block — user sees an infinite spinner on failure.

When repository.createClient(clientPayload) throws, the error is parsed but the UI state remains ShowProgressbar. The user has no way to recover.

🐛 Proposed fix
             } catch (e: Exception) {
-                MFErrorParser.errorMessage(e)
+                _createNewClientUiState.value =
+                    CreateNewClientUiState.ShowStringError(
+                        MFErrorParser.errorMessage(e),
+                    )
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt`
around lines 165 - 167, The catch block in CreateNewClientViewModel currently
only calls MFErrorParser.errorMessage(e) and leaves the UI stuck in
ShowProgressbar; update the catch to set the view model's UI state to hide the
progress indicator and surface the error (e.g., set state from ShowProgressbar
to an Error/Idle state containing MFErrorParser.errorMessage(e) and/or an error
flag/message) so the spinner stops and the user can retry; locate the catch
inside the coroutine that calls repository.createClient(clientPayload) and set
the appropriate state backing property (e.g., _state or uiState) and/or call a
method like showError(...) to apply the parsed message.
🧹 Nitpick comments (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientUiState.kt (1)

29-29: Minor naming inconsistency: clientId here vs. id in SetClientId.

OnImageUploadSuccess uses clientId (line 29) while SetClientId uses id (line 39). Both carry the same client identifier. Consider aligning the naming for consistency across the sealed class.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientUiState.kt`
at line 29, Rename the parameter in the CreateNewClientUiState subclass to keep
the client identifier name consistent: update OnImageUploadSuccess to use the
same property name as SetClientId (e.g., change its parameter from clientId to
id) and update any usages/places that construct or deconstruct
OnImageUploadSuccess accordingly so all sealed subclasses (OnImageUploadSuccess
and SetClientId) use the identical identifier name (id).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt`:
- Around line 378-379: The onFinish handler currently uses
navController::popBackStack which returns the user to the completed Create
Client screen; change onFinish to navigate away from that screen instead (e.g.,
call navController.popBackStack to the client list or use navController.navigate
to the newly-created client's profile) so the Create Client screen is removed
from the back stack; update the component wiring where onFinish is passed (look
for the onFinish parameter usage and the call site that also invokes
navigateToCreateLoanAccount and the navController::popBackStack binding) to pop
back to the client list route or navigate forward to the client profile with the
created client ID rather than popping to the Create Client route.
- Around line 185-189: The call site passes
navController::navigateToNewLoanAccountRoute (signature (Int, String) -> Unit)
where createClientRoute expects a (Int) -> Unit; replace the method reference
with a lambda that matches (Int) -> Unit, e.g. navigateToCreateLoanAccount = {
clientId -> navController.navigateToNewLoanAccountRoute(clientId, /*accountNo*/
) }, and supply the appropriate accountNo (either derive it from the surrounding
scope/state or add a parameter to the callback path so the UI can pass the
account number) so createClientRoute and navigateToNewLoanAccountRoute
signatures align.
- Around line 377-381: Remove the duplicate registration of the NewLoanAccount
composable by deleting the extra call to newLoanAccountDestination(...) in
ClientNavigation.kt (the block that passes onNavigateBack =
navController::popBackStack, onFinish = navController::popBackStack,
navController = navController); keep the existing loanDestination(...) call
which already registers newLoanAccountDestination internally (do not touch
loanDestination implementation in LoanNavigation.kt).

---

Outside diff comments:
In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`:
- Around line 233-239: The navigation call is happening during composition in
CreateNewClientScreen: when handling CreateNewClientUiState.SetClientId the code
calls navigateToCreateLoanAccount(uiState.id) (or uploadImage(uiState.id))
directly which will re-fire on every recomposition; wrap the side-effectful
calls in a LaunchedEffect keyed on the unique id (e.g., uiState.id) or the state
to ensure the action runs only once per new id—move the
navigateToCreateLoanAccount(uiState.id) and uploadImage(uiState.id) calls into
that LaunchedEffect block so composition no longer triggers navigation/upload
repeatedly.
- Around line 250-258: The code is launching a snackbar and calling
navigateToCreateLoanAccount during composition for
CreateNewClientUiState.OnImageUploadSuccess which causes duplicate side-effects
on recomposition; wrap the side-effects in a Compose side-effect such as
LaunchedEffect keyed to the success event (e.g., LaunchedEffect(uiState) or
LaunchedEffect(uiState.clientId) and check uiState is
CreateNewClientUiState.OnImageUploadSuccess inside it), then call
snackbarHostState.showSnackbar(...) and
navigateToCreateLoanAccount(uiState.clientId) from within that LaunchedEffect so
both the snackbarHostState.showSnackbar and navigateToCreateLoanAccount are
executed exactly once when the success state appears instead of on every
recomposition.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt`:
- Around line 155-160: The current use of delay(1000) between setting
_createNewClientUiState to CreateNewClientUiState.ShowClientCreatedSuccessfully
and then emitting CreateNewClientUiState.SetClientId is fragile: it races with
snackbar display, is cancelled silently, and StateFlow replay will re-trigger
navigation on restore. Replace this pattern with a one-time event channel or
shared flow (e.g., a Channel or MutableSharedFlow(replay = 0)) for navigation
events, emitting the client id into that one-time stream instead of encoding it
in _createNewClientUiState; alternatively, let the UI call a ViewModel method
(e.g., onSnackbarDismissed) to trigger emitting SetClientId so the UI drives the
timing rather than a fixed delay.
- Around line 165-167: The catch block in CreateNewClientViewModel currently
only calls MFErrorParser.errorMessage(e) and leaves the UI stuck in
ShowProgressbar; update the catch to set the view model's UI state to hide the
progress indicator and surface the error (e.g., set state from ShowProgressbar
to an Error/Idle state containing MFErrorParser.errorMessage(e) and/or an error
flag/message) so the spinner stops and the user can retry; locate the catch
inside the coroutine that calls repository.createClient(clientPayload) and set
the appropriate state backing property (e.g., _state or uiState) and/or call a
method like showError(...) to apply the parsed message.

---

Nitpick comments:
In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientUiState.kt`:
- Line 29: Rename the parameter in the CreateNewClientUiState subclass to keep
the client identifier name consistent: update OnImageUploadSuccess to use the
same property name as SetClientId (e.g., change its parameter from clientId to
id) and update any usages/places that construct or deconstruct
OnImageUploadSuccess accordingly so all sealed subclasses (OnImageUploadSuccess
and SetClientId) use the identical identifier name (id).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1467aa2 and f2b6c97.

📒 Files selected for processing (5)
  • cmp-navigation/src/commonMain/kotlin/cmp/navigation/authenticated/AuthenticatedNavbarNavigationScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientUiState.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt

@itsPronay
itsPronay force-pushed the client-loan-account-flow branch from f2b6c97 to 03c97be Compare February 23, 2026 14:51

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt (1)

233-258: ⚠️ Potential issue | 🔴 Critical

Navigation and uploadImage called directly during Composable composition — causes infinite re-navigation on back press.

Lines 237, 257, and 235 invoke side effects (navigateToCreateLoanAccount, uploadImage) directly inside a when branch that runs on every recomposition. Two concrete bugs result:

  1. Infinite navigation loop: navigateToCreateLoanAccount is called during composition. The ViewModel's SetClientId / OnImageUploadSuccess state is never reset after the call. When the user presses Back from the loan-account screen, the CreateNewClientScreen recomposes with the same state → navigation fires again → the user is immediately pushed forward again, with no way to go back.

  2. Repeated uploadImage calls: if selectedImage is null at the time of composition (early return in uploadImage without a state change), the state stays SetClientId and uploadImage is invoked on every recomposition until the image is actually set.

The fix requires two coordinated changes:

In CreateNewClientScreen — wrap both side effects in LaunchedEffect:

🐛 Proposed fix — screen side
 is CreateNewClientUiState.SetClientId -> {
-    if (createClientWithImage) {
-        uploadImage(uiState.id)
-    } else {
-        navigateToCreateLoanAccount(uiState.id)
+    LaunchedEffect(uiState.id) {
+        if (createClientWithImage) {
+            uploadImage(uiState.id)
+        } else {
+            navigateToCreateLoanAccount(uiState.id)
+        }
     }
 }
 ...
 is CreateNewClientUiState.OnImageUploadSuccess -> {
     scope.launch {
         snackbarHostState.showSnackbar(
             message = getString(Res.string.feature_client_Image_Upload_Successful),
             duration = SnackbarDuration.Long,
         )
     }
-    navigateToCreateLoanAccount(uiState.clientId)
+    LaunchedEffect(uiState.clientId) {
+        navigateToCreateLoanAccount(uiState.clientId)
+    }
 }

In CreateNewClientViewModel — reset state after the navigation event is consumed (e.g., back to ShowProgressbar or a dedicated Idle state) so that a back-navigation does not re-trigger the side effect:

// After emitting SetClientId, reset to avoid re-trigger on back press
_createNewClientUiState.value = CreateNewClientUiState.ShowProgressbar

Without the ViewModel reset, even LaunchedEffect will re-run in a new composition lifecycle (i.e., after back-navigation), so both halves of the fix are needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`
around lines 233 - 258, Wrap composition-only side effects in the Composable by
moving calls to uploadImage(...) and navigateToCreateLoanAccount(...) into
LaunchedEffect blocks inside CreateNewClientScreen so they only run when the
relevant state value changes (use uiState.id or uiState.clientId as the key)
instead of invoking them directly during when-branch composition; additionally,
modify CreateNewClientViewModel to reset _createNewClientUiState after emitting
terminal states (e.g., after emitting CreateNewClientUiState.SetClientId or
OnImageUploadSuccess set _createNewClientUiState to
CreateNewClientUiState.ShowProgressbar or a dedicated Idle state) so the event
is consumed and back-navigation does not re-trigger the side effect.
🧹 Nitpick comments (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt (1)

159-160: Extract the magic-number delay to a named constant.

The 1000 ms literal is unexplained. If the value ever needs to change (or be adjusted per platform), there's no single place to update it.

♻️ Suggested refactor
+private const val CLIENT_CREATION_NAVIGATION_DELAY_MS = 1_000L

 ...
-                    delay(1000)
+                    delay(CLIENT_CREATION_NAVIGATION_DELAY_MS)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt`
around lines 159 - 160, Replace the hardcoded delay(1000) in
CreateNewClientViewModel with a named constant (e.g., CLIENT_ID_DELAY_MS) so the
purpose is clear and it can be adjusted per platform; declare the constant near
the class (or companion object) and use it in place of 1000 where delay(...) is
called before setting _createNewClientUiState to
CreateNewClientUiState.SetClientId(it).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt`:
- Line 187: The binding for navigateToCreateLoanAccount is calling
navController::navigateToNewLoanAccountRoute but that target requires two
parameters (fun NavController.navigateToNewLoanAccountRoute(clientId: Int,
accountNo: String)); change the assignment to a lambda that accepts both
clientId and accountNo and calls
navController.navigateToNewLoanAccountRoute(clientId, accountNo) so both
arguments are passed when invoking the navigation function.

---

Outside diff comments:
In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`:
- Around line 233-258: Wrap composition-only side effects in the Composable by
moving calls to uploadImage(...) and navigateToCreateLoanAccount(...) into
LaunchedEffect blocks inside CreateNewClientScreen so they only run when the
relevant state value changes (use uiState.id or uiState.clientId as the key)
instead of invoking them directly during when-branch composition; additionally,
modify CreateNewClientViewModel to reset _createNewClientUiState after emitting
terminal states (e.g., after emitting CreateNewClientUiState.SetClientId or
OnImageUploadSuccess set _createNewClientUiState to
CreateNewClientUiState.ShowProgressbar or a dedicated Idle state) so the event
is consumed and back-navigation does not re-trigger the side effect.

---

Nitpick comments:
In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt`:
- Around line 159-160: Replace the hardcoded delay(1000) in
CreateNewClientViewModel with a named constant (e.g., CLIENT_ID_DELAY_MS) so the
purpose is clear and it can be adjusted per platform; declare the constant near
the class (or companion object) and use it in place of 1000 where delay(...) is
called before setting _createNewClientUiState to
CreateNewClientUiState.SetClientId(it).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f2b6c97 and bbc89f5.

📒 Files selected for processing (5)
  • cmp-navigation/src/commonMain/kotlin/cmp/navigation/authenticated/AuthenticatedNavbarNavigationScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientUiState.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientViewModel.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientUiState.kt
  • cmp-navigation/src/commonMain/kotlin/cmp/navigation/authenticated/AuthenticatedNavbarNavigationScreen.kt

@IOhacker

Copy link
Copy Markdown
Contributor

There is one issue with this file

file:///home/runner/work/android-client/android-client/feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt:187:58 Inapplicable candidate(s): fun NavController.navigateToNewLoanAccountRoute(clientId: Int, accountNo: String): Unit

@itsPronay

Copy link
Copy Markdown
Member Author

@IOhacker yeah, it looks like changes were made recently in that file. I didn’t have those changes locally, so it was building fine for me.
I’ve pulled the latest changes and fixed it.

@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: 1

> [!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/newLoanAccount/NewLoanAccountRoute.kt (1)

37-41: ⚠️ Potential issue | 🔴 Critical

Fix compile-time signature mismatch at ClientNavigation.kt line 351

The function navigateToNewLoanAccountRoute has signature (clientId: Int, accountNo: String? = null), but at line 351 it's passed to a parameter expecting (Int, String) -> Unit where accountNo is non-nullable and required. Making the parameter optional breaks this contract.

Either update the parameter type at line 26 of ClientApplyNewApplicationRoute.kt to (Int, String?) -> Unit, or update the call site at line 351 to pass an adapter that supplies the required String parameter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountRoute.kt`
around lines 37 - 41, The compile error comes from a function-type mismatch:
navigateToNewLoanAccountRoute(clientId: Int, accountNo: String? = null) exposes
a nullable optional accountNo but is being assigned where a handler of type
(Int, String) -> Unit (non-nullable accountNo) is required (the consumer is
ClientApplyNewApplicationRoute's callback). Fix by either changing the consumer
signature in ClientApplyNewApplicationRoute from (Int, String) -> Unit to (Int,
String?) -> Unit so it accepts nullable accountNo, or change the call site that
provides navigateToNewLoanAccountRoute to wrap/adapter it into a (Int, String)
-> Unit by supplying a non-null String (e.g., map null to "" or some default)
before calling NewLoanAccountRoute; update references to the symbols
navigateToNewLoanAccountRoute and ClientApplyNewApplicationRoute accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountRoute.kt`:
- Line 20: The nullable property accountNo in NewLoanAccountRoute is currently
declared as "val accountNo: String?" which makes it a required path parameter in
Compose Navigation; change its declaration to include a default "= null" so it
becomes an optional query parameter (e.g., "val accountNo: String? = null").
Update any constructors or usages that rely on positional routing to handle the
optional query form (look for NewLoanAccountRoute and any route
builders/arguments referencing accountNo) so navigation can omit the parameter
without producing an invalid URI.

---

Outside diff comments:
In
`@feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountRoute.kt`:
- Around line 37-41: The compile error comes from a function-type mismatch:
navigateToNewLoanAccountRoute(clientId: Int, accountNo: String? = null) exposes
a nullable optional accountNo but is being assigned where a handler of type
(Int, String) -> Unit (non-nullable accountNo) is required (the consumer is
ClientApplyNewApplicationRoute's callback). Fix by either changing the consumer
signature in ClientApplyNewApplicationRoute from (Int, String) -> Unit to (Int,
String?) -> Unit so it accepts nullable accountNo, or change the call site that
provides navigateToNewLoanAccountRoute to wrap/adapter it into a (Int, String)
-> Unit by supplying a non-null String (e.g., map null to "" or some default)
before calling NewLoanAccountRoute; update references to the symbols
navigateToNewLoanAccountRoute and ClientApplyNewApplicationRoute accordingly.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bbc89f5 and 591456c.

📒 Files selected for processing (2)
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountRoute.kt
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt

@itsPronay
itsPronay force-pushed the client-loan-account-flow branch from 591456c to cf15cc1 Compare February 23, 2026 16:02
@itsPronay
itsPronay force-pushed the client-loan-account-flow branch from f64ab59 to b85ce6a Compare February 24, 2026 15:56

@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.

Caution

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

⚠️ Outside diff range comments (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt (1)

233-238: ⚠️ Potential issue | 🟠 Major

Guard navigation/upload side effects against recomposition.

uploadImage(...) and navigateToCreateLoanAccount(...) in SetClientId are triggered directly during composition without guards. In OnImageUploadSuccess, the navigateToCreateLoanAccount(uiState.clientId) call at line 256 is outside the scope.launch block and also executes during composition. Since these states are not reset after emission, any recomposition will re-execute these side effects, risking duplicate uploads and navigation. Wrap them in LaunchedEffect keyed on the state/id.

♻️ Suggested fix using LaunchedEffect
 is CreateNewClientUiState.SetClientId -> {
-    if (createClientWithImage) {
-        uploadImage(uiState.id)
-    } else {
-        navigateToCreateLoanAccount(uiState.id)
-    }
+    LaunchedEffect(uiState.id, createClientWithImage) {
+        if (createClientWithImage) {
+            uploadImage(uiState.id)
+        } else {
+            navigateToCreateLoanAccount(uiState.id)
+        }
+    }
 }
 
 is CreateNewClientUiState.OnImageUploadSuccess -> {
-    scope.launch {
-        snackbarHostState.showSnackbar(
-            message = getString(Res.string.feature_client_Image_Upload_Successful),
-            duration = SnackbarDuration.Long,
-        )
-    }
-    navigateToCreateLoanAccount(uiState.clientId)
+    LaunchedEffect(uiState.clientId) {
+        snackbarHostState.showSnackbar(
+            message = getString(Res.string.feature_client_Image_Upload_Successful),
+            duration = SnackbarDuration.Long,
+        )
+        navigateToCreateLoanAccount(uiState.clientId)
+    }
 }

Also applies to: 250-258

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`
around lines 233 - 238, The SetClientId branch currently calls
uploadImage(uiState.id) or navigateToCreateLoanAccount(uiState.id) directly
during composition (and OnImageUploadSuccess calls
navigateToCreateLoanAccount(uiState.clientId) outside scope.launch), causing
duplicate side-effects on recomposition; wrap these calls in LaunchedEffect
keyed on the unique id/state (e.g., LaunchedEffect(uiState.id) or
LaunchedEffect(uiState.clientId)) and move any suspend work (scope.launch logic)
inside that LaunchedEffect so uploadImage(...) and
navigateToCreateLoanAccount(...) are only invoked once per emitted state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`:
- Around line 233-238: The SetClientId branch currently calls
uploadImage(uiState.id) or navigateToCreateLoanAccount(uiState.id) directly
during composition (and OnImageUploadSuccess calls
navigateToCreateLoanAccount(uiState.clientId) outside scope.launch), causing
duplicate side-effects on recomposition; wrap these calls in LaunchedEffect
keyed on the unique id/state (e.g., LaunchedEffect(uiState.id) or
LaunchedEffect(uiState.clientId)) and move any suspend work (scope.launch logic)
inside that LaunchedEffect so uploadImage(...) and
navigateToCreateLoanAccount(...) are only invoked once per emitted state.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 591456c and b85ce6a.

📒 Files selected for processing (2)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt

@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.

Caution

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

⚠️ Outside diff range comments (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt (1)

232-257: ⚠️ Potential issue | 🟠 Major

Navigation side effects called directly in composition — will fire on every recomposition

Both navigateToCreateLoanAccount(uiState.id) (line 236) and navigateToCreateLoanAccount(uiState.clientId) (line 256) are invoked in the composition body, outside any LaunchedEffect. While the state machine may make it rare, any recomposition triggered while the ViewModel is still emitting either SetClientId or OnImageUploadSuccess (e.g., due to a layout pass, a system-level configuration change, or a parent recomposing) will re-execute navigation, silently stacking duplicate destinations onto the back stack.

The same pattern exists pre-existingly at lines 234 (uploadImage), 241/250/260 (scope.launch), and 266 (navigateBack.invoke()), but the new navigation calls make this actively worse because corrupted back stacks are harder to recover from than repeated snackbars.

The fix is to wrap the entire branch body in a LaunchedEffect keyed on the stable ID. Doing so in OnImageUploadSuccess also lets the snackbar complete before navigating away, which is the intended UX:

🐛 Proposed fix
             is CreateNewClientUiState.SetClientId -> {
-                if (createClientWithImage) {
-                    uploadImage(uiState.id)
-                } else {
-                    navigateToCreateLoanAccount(uiState.id)
+                LaunchedEffect(uiState.id) {
+                    if (createClientWithImage) {
+                        uploadImage(uiState.id)
+                    } else {
+                        navigateToCreateLoanAccount(uiState.id)
+                    }
                 }
             }

             is CreateNewClientUiState.OnImageUploadSuccess -> {
-                scope.launch {
-                    snackbarHostState.showSnackbar(
-                        message = getString(Res.string.feature_client_Image_Upload_Successful),
-                        duration = SnackbarDuration.Long,
-                    )
-                }
-                navigateToCreateLoanAccount(uiState.clientId)
+                LaunchedEffect(uiState.clientId) {
+                    snackbarHostState.showSnackbar(
+                        message = getString(Res.string.feature_client_Image_Upload_Successful),
+                        duration = SnackbarDuration.Long,
+                    )
+                    navigateToCreateLoanAccount(uiState.clientId)
+                }
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`
around lines 232 - 257, The navigation and other side effects in the
CreateNewClientUiState.SetClientId and
CreateNewClientUiState.OnImageUploadSuccess branches (calls to
navigateToCreateLoanAccount(uiState.id / uiState.clientId),
uploadImage(uiState.id), and snackbarHostState.showSnackbar) must be moved out
of the direct composition and executed inside LaunchedEffect blocks keyed on the
stable id (uiState.id or uiState.clientId); wrap each branch body in
LaunchedEffect(key1 = uiState.id/clientId) and perform uploadImage, showSnackbar
and then call navigateToCreateLoanAccount from inside that coroutine so the
snackbar can complete before navigation and to prevent repeated navigation on
recomposition.
🧹 Nitpick comments (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt (1)

154-168: Parameter naming inconsistency between the route wrapper and the inner composable

CreateNewClientScreenRoute exposes navigateToClientDetails: (Int) -> Unit (line 156), but it is threaded into CreateNewClientScreen under the name navigateToCreateLoanAccount (lines 168, 189). "Navigate to client details" and "navigate to create loan account" describe different destinations — a reader of either function's signature gets contradictory information about where navigation actually leads.

Pick one name that reflects the true destination (loan account creation) and apply it consistently at both levels.

♻️ Proposed rename
 internal fun CreateNewClientScreenRoute(
     navigateBack: () -> Unit,
-    navigateToClientDetails: (Int) -> Unit,
+    navigateToCreateLoanAccount: (Int) -> Unit,
     hasDatatables: (datatables: List<DataTableEntity>, clientPayload: ClientPayloadEntity) -> Unit,
     viewmodel: CreateNewClientViewModel = koinViewModel(),
 ) {
     ...
     CreateNewClientScreen(
         ...
-        navigateToCreateLoanAccount = navigateToClientDetails,
+        navigateToCreateLoanAccount = navigateToCreateLoanAccount,
         ...
     )
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`
around lines 154 - 168, The route wrapper CreateNewClientScreenRoute currently
takes a parameter named navigateToClientDetails but passes it into the inner
composable CreateNewClientScreen as navigateToCreateLoanAccount, causing a
naming inconsistency; decide the true destination is loan account creation,
rename the parameter in CreateNewClientScreenRoute from navigateToClientDetails
to navigateToCreateLoanAccount (and update all call sites) and also rename the
parameter in CreateNewClientScreen signature if needed so both functions use the
same name (navigateToCreateLoanAccount) and type ((Int)->Unit) for clear,
consistent navigation intent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`:
- Around line 232-257: The navigation and other side effects in the
CreateNewClientUiState.SetClientId and
CreateNewClientUiState.OnImageUploadSuccess branches (calls to
navigateToCreateLoanAccount(uiState.id / uiState.clientId),
uploadImage(uiState.id), and snackbarHostState.showSnackbar) must be moved out
of the direct composition and executed inside LaunchedEffect blocks keyed on the
stable id (uiState.id or uiState.clientId); wrap each branch body in
LaunchedEffect(key1 = uiState.id/clientId) and perform uploadImage, showSnackbar
and then call navigateToCreateLoanAccount from inside that coroutine so the
snackbar can complete before navigation and to prevent repeated navigation on
recomposition.

---

Nitpick comments:
In
`@feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt`:
- Around line 154-168: The route wrapper CreateNewClientScreenRoute currently
takes a parameter named navigateToClientDetails but passes it into the inner
composable CreateNewClientScreen as navigateToCreateLoanAccount, causing a
naming inconsistency; decide the true destination is loan account creation,
rename the parameter in CreateNewClientScreenRoute from navigateToClientDetails
to navigateToCreateLoanAccount (and update all call sites) and also rename the
parameter in CreateNewClientScreen signature if needed so both functions use the
same name (navigateToCreateLoanAccount) and type ((Int)->Unit) for clear,
consistent navigation intent.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b85ce6a and 8a56c4f.

📒 Files selected for processing (2)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createNewClient/CreateNewClientScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt

@itsPronay
itsPronay force-pushed the client-loan-account-flow branch from 8a56c4f to 542f611 Compare February 24, 2026 16:23

@therajanmaurya therajanmaurya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I will review today

@therajanmaurya therajanmaurya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Code Review

Summary

This PR enhances the client creation workflow by navigating to the loan account creation screen after a client is successfully created, enabling a streamlined "one-shot" flow for creating both client and loan.

Code Walkthrough

File Changes
AuthenticatedNavbarNavigationScreen.kt Simplified onNavigateToSearch callback to method reference
CreateNewClientScreen.kt Renamed to CreateNewClientScreenRoute, added navigation callback
CreateNewClientUiState.kt Added clientId parameter to OnImageUploadSuccess
CreateNewClientViewModel.kt Added delay before navigation, moved init to init block
ClientNavigation.kt Wired navigation to client profile route

Findings

Major

  1. CreateNewClientScreen.kt:233-237 - Side effects called directly during composition

    The navigation calls navigateToClientDetails(uiState.id) and uploadImage(uiState.id) are invoked directly in the when branch during composition. If recomposition occurs while the ViewModel emits SetClientId, navigation fires multiple times.

    Suggested Fix
    is CreateNewClientUiState.SetClientId -> {
        LaunchedEffect(uiState.id) {
            if (createClientWithImage) {
                uploadImage(uiState.id)
            } else {
                navigateToClientDetails(uiState.id)
            }
        }
    }
  2. CreateNewClientScreen.kt:250-257 - Same recomposition issue in OnImageUploadSuccess

    navigateToClientDetails(uiState.clientId) is called outside LaunchedEffect, causing potential duplicate navigation.

    Suggested Fix
    is CreateNewClientUiState.OnImageUploadSuccess -> {
        LaunchedEffect(uiState.clientId) {
            snackbarHostState.showSnackbar(
                message = getString(Res.string.feature_client_Image_Upload_Successful),
                duration = SnackbarDuration.Long,
            )
            navigateToClientDetails(uiState.clientId)
        }
    }

Minor

  1. CreateNewClientViewModel.kt:159 - Extract magic number delay(1000) to a named constant like NAVIGATION_DELAY_MS

Architecture Compliance

Check Status
MVI Pattern ✅ Uses StateFlow + sealed UiState
Single Responsibility ✅ Screen, ViewModel, Navigation separated

Test Coverage

  • No test changes included - consider adding ViewModel tests for new state transitions

Security

  • No hardcoded secrets
  • No injection vulnerabilities

Recommendation: Address the LaunchedEffect issues before merge to prevent navigation bugs on recomposition.

@therajanmaurya therajanmaurya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Code Review

Summary

This PR enhances the client creation flow by navigating directly to the newly created client's details page instead of just going back. It also moves the loadOfficeAndClientTemplate() call from LaunchedEffect to ViewModel's init block.

Code Walkthrough

  1. CreateNewClientScreen.kt (UI Layer)

    • Renamed CreateNewClientScreenCreateNewClientScreenRoute for clarity
    • Added navigateToClientDetails: (Int) -> Unit callback
    • After client creation, navigates to client details instead of going back
    • Removed LaunchedEffect for loading data (moved to ViewModel init)
  2. CreateNewClientViewModel.kt (ViewModel)

    • Moved loadOfficeAndClientTemplate() to init block
    • Added delay(1000) before transitioning to SetClientId state
    • Added clientId parameter to OnImageUploadSuccess state
  3. CreateNewClientUiState.kt (State)

    • OnImageUploadSuccess now includes clientId: Int for navigation
  4. ClientNavigation.kt (Navigation)

    • Added navigateToClientDetails parameter to createClientRoute
    • Wired navigation to navigateToClientDetailsProfileRoute
  5. AuthenticatedNavbarNavigationScreen.kt (Minor)

    • Simplified lambda to method reference

Findings Overview

Major [2 issues]

  • 🟠 CreateNewClientScreen.kt:232-237 [85% confidence]
    Navigation is called during composition in the SetClientId when branch. This will cause navigation to be triggered on every recomposition. Should be wrapped in LaunchedEffect.

  • 🟠 CreateNewClientScreen.kt:249-257 [85% confidence]
    Same issue in OnImageUploadSuccess branch - navigateToClientDetails(uiState.clientId) is called during composition, not in a side-effect handler.

Minor [1 issue]

  • 🟡 CreateNewClientViewModel.kt:159 [75% confidence]
    The delay(1000) is a hardcoded magic number. Consider extracting to a named constant like CLIENT_CREATION_SUCCESS_DELAY_MS for clarity and maintainability.

Suggested Fix for Navigation Issue

// Current (problematic):
is CreateNewClientUiState.SetClientId -> {
    if (createClientWithImage) {
        uploadImage(uiState.id)
    } else {
        navigateToClientDetails(uiState.id)  // ❌ Called during composition
    }
}

// Recommended:
is CreateNewClientUiState.SetClientId -> {
    LaunchedEffect(uiState.id) {
        if (createClientWithImage) {
            uploadImage(uiState.id)
        } else {
            navigateToClientDetails(uiState.id)  // ✅ Called as side-effect
        }
    }
}

Test Coverage

  • Unit tests for navigation callback
  • Test that SetClientId state triggers navigation exactly once

Security

  • No hardcoded secrets
  • No injection vulnerabilities
  • No sensitive data logging

Related Files Analyzed

File Purpose
ClientNavigation.kt Verified navigation destination exists
CreateNewClientUiState.kt Confirmed state changes
AuthenticatedNavbarNavigationScreen.kt Verified navigation wiring

@therajanmaurya therajanmaurya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good improvements to the client creation flow! The navigation to client details instead of going back is a better UX.

A couple of things to fix:

  1. Navigation during composition - The navigateToClientDetails() calls in both SetClientId and OnImageUploadSuccess branches are executing during composition. This will trigger on every recomposition - see my inline comments for the fix.

  2. Minor: The delay(1000) in ViewModel could use a named constant like CLIENT_CREATION_SUCCESS_DELAY_MS.

The ViewModel refactoring (moving loadOfficeAndClientTemplate() to init) is cleaner. Navigation wiring looks correct.

@therajanmaurya therajanmaurya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The changes look good overall - navigating to client details instead of just going back is a better UX.

Still needs fixing:

  1. The navigation calls at lines 236 and 256 are still being called during composition. I've left inline comments with the fix - wrap them in LaunchedEffect to ensure they only fire once.

The ViewModel refactoring (moving loadOfficeAndClientTemplate() to init) is cleaner.

@itsPronay
itsPronay force-pushed the client-loan-account-flow branch 2 times, most recently from b12c08b to 216d3f4 Compare March 2, 2026 16:24
@sonarqubecloud

sonarqubecloud Bot commented Mar 3, 2026

Copy link
Copy Markdown

@IOhacker

IOhacker commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

@therajanmaurya this PR looks fine from a functional perspective!

@therajanmaurya
therajanmaurya merged commit 89fa874 into openMF:development Mar 3, 2026
5 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.

6 participants