Skip to content

fix: Display Client Group Name and enable navigation#2571

Merged
therajanmaurya merged 3 commits intoopenMF:developmentfrom
kartikey004:fix/client-group-display
Jan 13, 2026
Merged

fix: Display Client Group Name and enable navigation#2571
therajanmaurya merged 3 commits intoopenMF:developmentfrom
kartikey004:fix/client-group-display

Conversation

@kartikey004
Copy link
Contributor

@kartikey004 kartikey004 commented Jan 8, 2026

Fixes - Jira-#375

Description - I implemented the functionality to display the Group Name in the Client Profile Screen and provided direct access to the Group.

Video:

Clients_GroupDisplay.mp4

Summary by CodeRabbit

  • New Features

    • Client profiles show a labeled, clickable group chip that navigates to group details; displays "N/A" when no group name is available.
    • Navigation updated to support jumping from a client to group details.
  • Bug Fixes / Improvements

    • Client data now surfaces group id/name when missing from the primary field, improving displayed group info.
  • Chores

    • Added dependency to enable group features.

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

@coderabbitai
Copy link

coderabbitai bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

Adds groupId and groupName fields to network and database models, maps them in the client mapper, enriches client data in the repository, and surfaces clickable group info in the client profile UI, ViewModel, and navigation to support navigating to group details.

Changes

Cohort / File(s) Summary
Database
core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt
Added nullable groupName: String? property to ClientEntity.
Network model
core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt
Added optional groupId: Int? and groupName: String? to response model.
Mapping
core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt
Mapped groupId and groupName in both directions between network model and entity.
Data repository
core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt
getClient() now fills groupId/groupName from the first group when groupName is blank and groups exist.
Feature dependency & resources
feature/client/build.gradle.kts, feature/client/src/commonMain/composeResources/values/strings.xml
Added feature.groups dependency and string resources group_na and group_label.
Navigation wiring
feature/client/src/commonMain/kotlin/.../clientProfile/ClientProfileNavigation.kt, feature/client/src/commonMain/kotlin/.../navigation/ClientNavigation.kt
Added navigateToGroupDetails: (Int) -> Unit parameter and forwarded it through client profile destination.
UI / Screen
feature/client/src/commonMain/kotlin/.../clientProfile/ClientProfileScreen.kt, feature/client/src/commonMain/kotlin/.../clientProfile/components/ProfileCard.kt
Added groupName display, a clickable GroupChip, updated ProfileCard signature, and wired onGroupClick to emit group navigation.
ViewModel / Events
feature/client/src/commonMain/kotlin/.../clientProfile/ClientProfileViewModel.kt
Added OnGroupClick(groupId: Int) action and NavigateToGroupDetails(groupId: Int) event; handler emits navigation event.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Screen as ClientProfileScreen
    participant VM as ClientProfileViewModel
    participant Nav as Navigation
    participant Group as GroupDetailsScreen

    User->>Screen: Tap GroupChip
    Screen->>VM: OnGroupClick(groupId)
    VM-->>Screen: Emit NavigateToGroupDetails(groupId)
    Screen->>Nav: navigateToGroupDetails(groupId)
    Nav->>Group: Open GroupDetails(groupId)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • biplab1
  • revanthkumarJ

Poem

🐇 I hopped through mappers, fields, and screens,
Poked a tiny group name in-between,
A little chip to press and click,
From profile card to group so quick,
Hooray — a hop, a route, a scene.

🚥 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 change: displaying client group name on the profile screen and enabling navigation to group details.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In
@core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt:
- Around line 85-96: getClient currently silently picks the first group when
groupName is blank, which is undocumented and uses !!; update getClient
(ClientDetailsRepositoryImp.getClient) to either document why the "first" group
is chosen (e.g., primary/default/most recent) with an inline comment above the
selection or refactor to handle multiple groups explicitly (e.g., determine
primary group logic or return all groups), and replace the unsafe groups!!
access with idiomatic safe calls such as groups.firstOrNull() and a null-check
before copying groupName/groupId so the code is clearer and safer.

In
@core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt:
- Around line 58-59: The mapping for groupId in ClientMapper
(GetClientsPageItemsResponse) uses domainModel.groupId?.toInt(), but the
response expects a Long like other ID fields; change the conversion to
domainModel.groupId?.toLong() (preserving nullability) so groupId is mapped as
Long in the GetClientsPageItemsResponse output.

In
@feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt:
- Around line 94-103: Avoid rendering "Group: null" and stop calling
stringResource on every recomposition: read the NA label once into a val (e.g.
val naLabel = stringResource(Res.string.group_na)), then conditionally render
GroupChip only when groupName != null && groupName != naLabel; inside that block
pass "Group: $groupName" to GroupChip, compute isClickable based on presence of
a real group (e.g. isClickable = onGroupClick != null) and keep onGroupClick as
before.
🧹 Nitpick comments (3)
core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt (1)

48-51: Consider updating the KDoc to include the new fields.

The groupId and groupName fields are appropriately nullable and positioned logically. However, the KDoc comment block at the top of the class (lines 15-27) should be updated to document these new parameters.

📝 Add KDoc entries for the new fields

Update the KDoc comment block to include:

 /**
  *
  *
  * @param accountNo
  * @param active
  * @param displayName
  * @param emailAddress
  * @param fullname
  * @param id
  * @param officeId
  * @param officeName
+ * @param groupId
+ * @param groupName
  * @param status
  */
feature/client/src/commonMain/composeResources/values/strings.xml (1)

391-391: Verify the string resource format is intentional.

The new group_na string resource contains only "N/A", while similar nearby resources (lines 387-390) follow the pattern "Label: N/A" (e.g., name_na, mobile_na, email_na, office_na).

If the label "Group:" is being added separately in the UI code, this format is fine. Otherwise, consider using a consistent format like <string name="group_na">Group: N/A</string> for consistency.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (1)

56-56: Consider using MifosCard's onClick parameter.

The current approach applies the clickable modifier directly. However, MifosCard already accepts an optional onClick parameter (as shown in the relevant code snippets) that conditionally applies clickable behavior, which is more idiomatic and consistent with the component's API design.

♻️ Proposed refactor
     MifosCard(
-        modifier = Modifier.clickable { onClick() },
+        onClick = onClick,
         colors = CardColors(
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f6e384 and c0c35ed.

📒 Files selected for processing (11)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt
  • core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt
  • feature/client/build.gradle.kts
  • feature/client/src/commonMain/composeResources/values/strings.xml
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileNavigation.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt
🧰 Additional context used
🧬 Code graph analysis (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (1)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosCard.kt (1)
  • MifosCard (32-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR Checks / Static Analysis Check
🔇 Additional comments (15)
feature/client/build.gradle.kts (1)

33-33: LGTM! Dependency correctly added for group navigation.

The addition of the feature.groups dependency is appropriate and necessary for implementing the group navigation functionality described in the PR objectives.

core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt (1)

61-62: LGTM! Field addition is appropriate.

The groupName field is correctly defined as nullable with a default null value, positioned logically after groupId. The implementation follows the existing pattern in the entity class.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt (2)

137-139: LGTM! Clean action-to-event mapping.

The group click action handling is implemented consistently with existing patterns in the ViewModel. The direct mapping from OnGroupClick to NavigateToGroupDetails is clear and appropriate.


176-176: Event and action definitions are well-structured.

The new group navigation event and action are properly defined and integrate cleanly with the existing sealed interfaces.

Also applies to: 194-194

core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt (1)

31-32: Mapping from entity to domain looks correct.

The groupId and groupName fields are properly extracted from the API response entity, with appropriate nullable handling.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileNavigation.kt (1)

31-31: Navigation parameter properly integrated.

The navigateToGroupDetails callback is correctly added to the navigation builder and propagated to ClientProfileScreen.

Also applies to: 44-44

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileScreen.kt (3)

60-60: Navigation callback properly added to screen signature.

The navigateToGroupDetails parameter integrates cleanly with the existing navigation callbacks.


107-109: Event handling for group navigation is correct.

The event properly extracts groupId and invokes the navigation callback.


168-173: Good null safety handling for group navigation.

The code properly checks for groupId presence before triggering navigation (lines 170-172), preventing null pointer issues. The fallback to "N/A" for groupName is appropriate. ProfileCard further ensures the group display is non-interactive when groupName is null or unavailable by using the isClickable flag (line 95-96) with the clickable modifier's enabled parameter (line 115).

feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt (2)

91-91: Import properly added.

The import for navigateToGroupDetailsScreen is correctly included.


197-199: Navigation wiring implemented correctly.

The navigateToGroupDetails callback properly invokes navigateToGroupDetailsScreen with the provided groupId, consistent with other navigation patterns in this file.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (4)

65-66: LGTM! Layout and styling improvements.

The layout changes (fillMaxWidth, weight(1f)) properly structure the card content, and the color adjustments using onPrimary with transparency provide consistent theming. The tint on the chevron icon completes the visual polish.

Also applies to: 76-76, 87-87, 92-92, 110-111


116-146: LGTM! Well-implemented chip component.

The GroupChip composable is cleanly implemented with proper:

  • Conditional clickability via the enabled parameter
  • Material Design styling (rounded shape, transparency-based background)
  • Icon-text layout with appropriate spacing
  • Design token usage for consistency

157-157: LGTM! Preview properly demonstrates new functionality.

The preview is updated to showcase the group display feature with a sample group name.


97-97: The string resource Res.string.group_na is properly defined and the data layer correctly handles null values by converting them to the "N/A" string. The clickability logic at line 97 is sound—it correctly disables the group chip when there is no group membership or when displaying "N/A". No issues found.

Comment on lines 94 to 106

Spacer(Modifier.height(DesignToken.padding.small))

val isClickable = groupName != null && groupName != stringResource(Res.string.group_na)

GroupChip(
text = "Group: $groupName",
isClickable = isClickable,
onClick = onGroupClick,
)
Copy link

@coderabbitai coderabbitai bot Jan 8, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix null handling and string resource comparison.

There are two critical issues:

  1. Null display bug: If groupName is null, line 100 will display "Group: null", which is poor UX.
  2. Inefficient string comparison: Line 97 calls stringResource on every recomposition and compares it to groupName. This has performance implications and localization issues—if the backend sends "N/A" in English but the resource is translated (e.g., "不适用"), the comparison will fail.

Recommendation: Conditionally render GroupChip only when there's a valid group name, rather than always rendering it and comparing strings.

🐛 Proposed fix to conditionally render GroupChip
                 Text(
                     text = office,
                     style = MifosTypography.bodySmall,
                     color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.8f),
                 )
-
-                Spacer(Modifier.height(DesignToken.padding.small))
-
-                val isClickable = groupName != null && groupName != stringResource(Res.string.group_na)
-
-                GroupChip(
-                    text = "Group: $groupName",
-                    isClickable = isClickable,
-                    onClick = onGroupClick,
-                )
+                
+                if (!groupName.isNullOrBlank()) {
+                    Spacer(Modifier.height(DesignToken.padding.small))
+                    
+                    val naText = stringResource(Res.string.group_na)
+                    val isClickable = groupName != naText
+                    
+                    GroupChip(
+                        text = "Group: $groupName",
+                        isClickable = isClickable,
+                        onClick = onGroupClick,
+                    )
+                }
             }

This approach:

  • Avoids displaying "Group: null"
  • Extracts stringResource call to a local variable (minor optimization)
  • Only renders the chip when there's meaningful group data
🤖 Prompt for AI Agents
In
@feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt
around lines 94 - 103, Avoid rendering "Group: null" and stop calling
stringResource on every recomposition: read the NA label once into a val (e.g.
val naLabel = stringResource(Res.string.group_na)), then conditionally render
GroupChip only when groupName != null && groupName != naLabel; inside that block
pass "Group: $groupName" to GroupChip, compute isClickable based on presence of
a real group (e.g. isClickable = onGroupClick != null) and keep onGroupClick as
before.

Copy link
Contributor

Choose a reason for hiding this comment

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

@kartikey004 Have you addressed this issue yet?

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kartikey004 Have you addressed this issue yet?

Yes. this issue is resolved.

@kartikey004 kartikey004 force-pushed the fix/client-group-display branch from c0c35ed to fc49707 Compare January 8, 2026 13:09
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
@core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt:
- Line 48: The GetClientsPageItemsResponse model defines groupId as Int? while
other ID fields (id, officeId) are Long? and GroupsDaoHelper.saveGroupAccounts()
converts group IDs to Long, indicating a mismatch; update the groupId property
in GetClientsPageItemsResponse from Int? to Long? to match the rest of the
response model (or, if the API contract truly returns Int, add a clear comment
documenting that and update GroupsDaoHelper accordingly) so types are consistent
across the model and DAO conversions.

In
@feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt:
- Around line 97-104: The "Group:" prefix is hardcoded in ProfileCard when
building the GroupChip text; add a new localized string resource (e.g.,
group_label) and replace the literal prefix with
stringResource(Res.string.group_label) combined with displayGroupName so
GroupChip receives a fully localized label. Update the relevant resource file
with group_label (and keep using existing group_na) and change the ProfileCard
usage where GroupChip is called (variable displayGroupName and onGroupClick) to
use the localized label instead of the hardcoded "Group:".
🧹 Nitpick comments (3)
core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt (1)

90-90: Consider edge case: empty string vs null.

The condition checks isNullOrBlank() which handles null, empty string, and whitespace. However, if the API explicitly returns an empty string for groupName, this might indicate "no group" rather than "use first group". Consider whether the fallback should only apply when groupName is null.

♻️ Alternative: Only fallback when groupName is null
-        if (client.groupName.isNullOrBlank() && !client.groups.isNullOrEmpty()) {
+        if (client.groupName == null && !client.groups.isNullOrEmpty()) {

This ensures the fallback only triggers when the API doesn't provide groupName at all, not when it explicitly provides an empty/blank value.

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

15-27: Update KDoc to include new parameters.

The KDoc parameter list should be updated to include the newly added groupId and groupName fields for completeness.

📝 Add missing KDoc parameters
  * @param officeId
  * @param officeName
+ * @param groupId
+ * @param groupName
  * @param status
feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (1)

117-147: Well-structured GroupChip implementation.

The composable follows Compose best practices with proper spacing, theming, and conditional clickability.

Optional enhancement: Consider adding visual differentiation for the non-clickable state to improve UX clarity, though the "N/A" text already provides semantic indication.

💡 Optional visual feedback enhancement
 @Composable
 private fun GroupChip(
     text: String,
     isClickable: Boolean,
     onClick: () -> Unit,
 ) {
     Box(
         modifier = Modifier
             .clip(DesignToken.shapes.small)
             .background(
-                color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.15f),
+                color = MaterialTheme.colorScheme.onPrimary.copy(
+                    alpha = if (isClickable) 0.15f else 0.08f
+                ),
             )
             .clickable(enabled = isClickable, onClick = onClick)
             .padding(horizontal = DesignToken.padding.small, vertical = DesignToken.padding.extraSmall),
     ) {
         Row(verticalAlignment = Alignment.CenterVertically) {
             Icon(
                 imageVector = MifosIcons.Group,
                 contentDescription = null,
                 modifier = Modifier.size(DesignToken.sizes.iconSmall),
-                tint = MaterialTheme.colorScheme.onPrimary,
+                tint = MaterialTheme.colorScheme.onPrimary.copy(
+                    alpha = if (isClickable) 1f else 0.5f
+                ),
             )
             Spacer(modifier = Modifier.width(DesignToken.padding.extraSmall))
             Text(
                 text = text,
                 style = MifosTypography.bodySmall.copy(fontWeight = FontWeight.Medium),
-                color = MaterialTheme.colorScheme.onPrimary,
+                color = MaterialTheme.colorScheme.onPrimary.copy(
+                    alpha = if (isClickable) 1f else 0.5f
+                ),
             )
         }
     }
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0c35ed and fc49707.

📒 Files selected for processing (11)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt
  • core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt
  • feature/client/build.gradle.kts
  • feature/client/src/commonMain/composeResources/values/strings.xml
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileNavigation.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt
🚧 Files skipped from review as they are similar to previous changes (7)
  • core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileNavigation.kt
  • feature/client/src/commonMain/composeResources/values/strings.xml
  • feature/client/build.gradle.kts
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt
🧰 Additional context used
🧬 Code graph analysis (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (1)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosCard.kt (1)
  • MifosCard (32-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR Checks / Static Analysis Check
🔇 Additional comments (7)
core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt (1)

31-32: LGTM! Clean bidirectional mapping.

The mapper correctly handles the new groupId and groupName fields in both directions, maintaining consistency with the existing mapping pattern.

Also applies to: 58-59

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

85-99: Verify the business logic assumption about using the first group as the primary group.

The implementation assumes the first group in the API response is the "primary" group to display for clients belonging to multiple groups. However, there is no evidence of:

  • API documentation specifying the order of groups returned
  • GroupEntity having a primary/priority field to identify the main group
  • Tests validating this assumption

Confirm this business rule with the product team before merging, as relying on API response ordering without explicit documentation may cause incorrect group assignments for multi-group clients.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (5)

12-42: LGTM! Imports are appropriate.

All new imports are necessary for the added group display and navigation functionality.


51-52: LGTM! Backward-compatible signature extension.

The optional parameters with sensible defaults maintain backward compatibility while enabling the new group navigation feature.


56-56: LGTM! Cleaner inline modifier.

The simplified clickable modifier is more concise and idiomatic.


87-93: LGTM! Improved color consistency.

The color updates create better visual hierarchy and adhere to Material Design principles by using onPrimary with appropriate alpha values for the primary-colored card.

Also applies to: 111-111


158-158: LGTM! Preview updated with new parameter.

Good practice to include the new groupName parameter in the preview for development visualization.


val officeName: String? = null,

val groupId: Int? = null,
Copy link

@coderabbitai coderabbitai bot Jan 8, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the specific file and its context around line 48
cat -n core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt | head -60

Repository: openMF/android-client

Length of output: 1765


🏁 Script executed:

# Search for all ID field types in response models
rg --type=kt 'val.*Id.*:.*\(Int\?|Long\?|String\?)' core/network/src/commonMain/kotlin/com/mifos/core/network/model/ -A 1 -B 1

Repository: openMF/android-client

Length of output: 187


🏁 Script executed:

# Look for Group entity definitions
fd -e kt -path '*/model/*' | xargs rg -l 'class Group|data class Group' | head -5

Repository: openMF/android-client

Length of output: 699


🏁 Script executed:

# Search for groupId usage patterns across the codebase
rg --type=kt 'groupId' core/ -B 2 -A 2 | head -100

Repository: openMF/android-client

Length of output: 91


🏁 Script executed:

# Search for Group entity definitions
rg 'class Group|data class Group' --max-count=10 core/

Repository: openMF/android-client

Length of output: 2227


🏁 Script executed:

# Search for groupId usage to understand the type pattern
rg 'groupId' --max-count=30 core/network/src/commonMain/kotlin/com/mifos/core/network/model/

Repository: openMF/android-client

Length of output: 189


🏁 Script executed:

# Look at how other ID fields are typed across different response models
rg 'val.*Id.*:.*Long|val.*Id.*:.*Int' core/network/src/commonMain/kotlin/com/mifos/core/network/model/ | head -30

Repository: openMF/android-client

Length of output: 3939


🏁 Script executed:

# Check if there's a Group response model or DTO
fd 'Group' core/network/src/commonMain/kotlin/com/mifos/core/network/model/ | xargs cat 2>/dev/null | head -100

Repository: openMF/android-client

Length of output: 2129


🏁 Script executed:

# Look at the actual Group entity in the model
cat core/model/src/commonMain/kotlin/com/mifos/core/model/objects/template/loan/Group.kt

Repository: openMF/android-client

Length of output: 1091


🏁 Script executed:

# Check database entities for Group and groupId types
cat core/database/src/commonMain/kotlin/com/mifos/room/entities/group/GroupEntity.kt

Repository: openMF/android-client

Length of output: 2358


🏁 Script executed:

# Search for how groupId is mapped or used in database/repository layers
rg 'groupId' core/database/ -B 2 -A 2 | head -50

Repository: openMF/android-client

Length of output: 5492


🏁 Script executed:

# Check client-related database entities to see groupId type there
rg 'groupId' core/model/ core/data/ -B 1 -A 1 | head -40

Repository: openMF/android-client

Length of output: 4317


The type inconsistency is confirmed; groupId is Int? while id and officeId are Long? in this response model. This differs from other ID field patterns in the codebase where primary entity IDs use Long. Additionally, the database layer explicitly converts groupId from Int to Long (see GroupsDaoHelper.saveGroupAccounts()), suggesting the codebase is aware of the mismatch. Align this field's type with other ID fields (Long?) or document the intentional difference if it reflects the API contract.

🤖 Prompt for AI Agents
In
@core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt
at line 48, The GetClientsPageItemsResponse model defines groupId as Int? while
other ID fields (id, officeId) are Long? and GroupsDaoHelper.saveGroupAccounts()
converts group IDs to Long, indicating a mismatch; update the groupId property
in GetClientsPageItemsResponse from Int? to Long? to match the rest of the
response model (or, if the API contract truly returns Int, add a clear comment
documenting that and update GroupsDaoHelper accordingly) so types are consistent
across the model and DAO conversions.

Copy link

Choose a reason for hiding this comment

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

@kartikey004, thank you for the clarification! If the backend API contract explicitly returns groupId as an Int, then keeping it as Int? in the response model is the correct approach to match the API contract. I appreciate you providing this context.


✏️ Learnings added
Learnt from: kartikey004
Repo: openMF/android-client PR: 2571
File: core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt:48-48
Timestamp: 2026-01-08T13:21:02.532Z
Learning: In the android-client codebase, the groupId field in GetClientsPageItemsResponse is intentionally typed as Int? (not Long?) because the backend API explicitly returns groupId as an Int, even though other ID fields like id and officeId use Long?.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@kartikey004 kartikey004 force-pushed the fix/client-group-display branch from fc49707 to 70dd220 Compare January 8, 2026 13:51
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (1)

98-106: Simplify isClickable logic.

The isClickable check compares groupName against the resolved localized string for group_na. This is fragile because the comparison depends on the runtime locale matching expectations. Since groupName is null when no group exists, checking !groupName.isNullOrBlank() alone should suffice.

♻️ Suggested simplification
 val displayGroupName = groupName ?: stringResource(Res.string.group_na)
-val isClickable = !groupName.isNullOrBlank() && groupName != stringResource(Res.string.group_na)
+val isClickable = !groupName.isNullOrBlank()
 val groupLabel = stringResource(Res.string.group_label)
core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt (1)

86-98: Approve with minor observation on redundancy.

The enrichment logic correctly populates group information from the first group when missing. However, there's a minor redundancy: after checking !client.groups.isNullOrEmpty(), the subsequent client.groups?.firstOrNull() will never return null (since we've confirmed the list is non-empty).

While the current code is safe and functional, you could simplify to:

if (client.groupName.isNullOrBlank()) {
    client.groups?.firstOrNull()?.let { firstGroup ->
        return client.copy(
            groupName = firstGroup.name,
            groupId = firstGroup.id,
        )
    }
}

The outer isNullOrEmpty check is redundant since firstOrNull() already handles null/empty lists gracefully.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fc49707 and 70dd220.

📒 Files selected for processing (11)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt
  • core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt
  • feature/client/build.gradle.kts
  • feature/client/src/commonMain/composeResources/values/strings.xml
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileNavigation.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt
🚧 Files skipped from review as they are similar to previous changes (5)
  • core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileNavigation.kt
  • feature/client/src/commonMain/composeResources/values/strings.xml
  • core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt
  • feature/client/build.gradle.kts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-08T13:21:02.532Z
Learnt from: kartikey004
Repo: openMF/android-client PR: 2571
File: core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt:48-48
Timestamp: 2026-01-08T13:21:02.532Z
Learning: In the android-client codebase, the groupId field in GetClientsPageItemsResponse is intentionally typed as Int? (not Long?) because the backend API explicitly returns groupId as an Int, even though other ID fields like id and officeId use Long?.

Applied to files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt
  • core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt
🧬 Code graph analysis (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (2)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosCard.kt (1)
  • MifosCard (32-55)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosScaffold.kt (1)
  • onClick (198-202)
🔇 Additional comments (5)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt (1)

91-91: LGTM!

The import and navigation wiring follow the established patterns in this file. The lambda correctly delegates to navigateToGroupDetailsScreen(groupId).

Also applies to: 197-199

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileScreen.kt (1)

168-173: LGTM!

The null-safety check on groupId before dispatching OnGroupClick is good defensive programming. This prevents navigation attempts when the group ID is unavailable.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt (1)

136-139: LGTM!

The action-to-event mapping follows the established ViewModel patterns. The OnGroupClick action correctly triggers a NavigateToGroupDetails event, maintaining consistency with other navigation flows like NavigateToClientDetailsScreen.

Also applies to: 175-176, 193-194

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (1)

119-149: LGTM!

The GroupChip composable is well-structured with proper use of clip before background for rounded corners, and the conditional clickability is correctly implemented via clickable(enabled = isClickable, ...).

core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt (1)

59-61: Database migration required; address type inconsistency for groupId across entities.

Adding a new column to a Room entity requires a database migration. With autoMigrations = [] and no explicit migration classes in the codebase, upgrading users will encounter a schema mismatch crash. Create a migration to add the groupName column.

Additionally, there is a type inconsistency for group IDs across entities:

  • ClientEntity.groupId is Int?
  • GroupDateEntity.groupId, SavingsAccountEntity.groupId, and LoanAccountEntity.groupId are all Long

The code explicitly converts groupId from Int to Long in GroupsDaoHelper (lines 121, 125). While ClientEntity.groupId is intentionally Int? per the backend API, the mismatch with other entities creates implicit type conversions. Ensure consistent handling of groupId types across all entities or document why ClientEntity differs.

Finally, consider defaulting groupId to null instead of 0 for consistency with groupName and other optional fields, unless 0 has specific semantic meaning in your system.

⛔ Skipped due to learnings
Learnt from: kartikey004
Repo: openMF/android-client PR: 2571
File: core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt:48-48
Timestamp: 2026-01-08T13:21:02.532Z
Learning: In the android-client codebase, the groupId field in GetClientsPageItemsResponse is intentionally typed as Int? (not Long?) because the backend API explicitly returns groupId as an Int, even though other ID fields like id and officeId use Long?.

@kartikey004 kartikey004 force-pushed the fix/client-group-display branch from 70dd220 to 9044c42 Compare January 8, 2026 14:01
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt (1)

15-27: Update KDoc to include the new parameters.

The KDoc @param section should be updated to document groupId and groupName for completeness.

📝 Suggested KDoc update
 /**
  *
  *
  * @param accountNo
  * @param active
  * @param displayName
  * @param emailAddress
  * @param fullname
  * @param id
  * @param officeId
  * @param officeName
+ * @param groupId
+ * @param groupName
  * @param status
  */
🤖 Fix all issues with AI agents
In
@core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt:
- Around line 61-62: The Room schema changed by adding ClientEntity.groupName
but MifosDatabase.VERSION wasn’t incremented and no migration exists; update the
database strategy by either bumping MifosDatabase.VERSION and adding a migration
object that migrates the old schema to include the new ClientEntity/groupName
column (implement migration and register it where migrations are provided) or,
if safe to discard local cache, enable fallbackToDestructiveMigration() in the
database builder; ensure you reference ClientEntity, the new groupName property,
and MifosDatabase.VERSION when making the change so the DB builder and migration
registry are updated consistently.
🧹 Nitpick comments (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileScreen.kt (1)

168-173: Consider edge case: groupName present but groupId null.

The GroupChip clickability is determined by groupName presence (in ProfileCard.kt line 99), but the click action here only triggers if groupId is non-null. If a client has a groupName but null groupId, the chip appears clickable but does nothing on tap.

Consider aligning the clickability check with groupId availability, or pass both values to ProfileCard and let it determine clickability based on groupId:

♻️ Suggested approach
 ProfileCard(
     image = state.profileImage,
     name = state.client?.displayName ?: stringResource(Res.string.name_na),
     accountNo = state.client?.accountNo
         ?: stringResource(Res.string.string_not_available),
     office = state.client?.officeName ?: stringResource(Res.string.office_na),
-    groupName = state.client?.groupName ?: stringResource(Res.string.group_na),
+    groupName = state.client?.groupName?.takeIf { state.client?.groupId != null }
+        ?: stringResource(Res.string.group_na),
     onGroupClick = {
         state.client?.groupId?.let { groupId ->
             onAction(ClientProfileAction.OnGroupClick(groupId))
         }
     },

This ensures groupName displays as "N/A" when there's no navigable groupId.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 70dd220 and 9044c42.

📒 Files selected for processing (11)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt
  • core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt
  • feature/client/build.gradle.kts
  • feature/client/src/commonMain/composeResources/values/strings.xml
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileNavigation.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileScreen.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.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)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileNavigation.kt
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-08T13:21:02.532Z
Learnt from: kartikey004
Repo: openMF/android-client PR: 2571
File: core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt:48-48
Timestamp: 2026-01-08T13:21:02.532Z
Learning: In the android-client codebase, the groupId field in GetClientsPageItemsResponse is intentionally typed as Int? (not Long?) because the backend API explicitly returns groupId as an Int, even though other ID fields like id and officeId use Long?.

Applied to files:

  • core/database/src/commonMain/kotlin/com/mifos/room/entities/client/ClientEntity.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt
  • core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt
🧬 Code graph analysis (1)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (1)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosCard.kt (1)
  • MifosCard (32-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR Checks / Static Analysis Check
🔇 Additional comments (12)
feature/client/build.gradle.kts (1)

33-33: LGTM!

The dependency on projects.feature.groups is correctly added to enable group navigation from the client profile screen.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt (2)

91-91: LGTM!

Import correctly added for the group details navigation function.


197-199: LGTM!

Navigation wiring for group details follows the established patterns in this file and correctly passes the groupId to the navigation function.

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

391-392: LGTM!

String resources are correctly added. The group_na having just "N/A" (unlike other *_na strings that include the field name) is intentional since ProfileCard concatenates group_label and the group name separately.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/components/ProfileCard.kt (2)

46-117: LGTM!

The ProfileCard extension with groupName and onGroupClick parameters is well-implemented. The clickability logic correctly disables navigation when the group name is null, blank, or "N/A".


119-149: LGTM!

The GroupChip composable is well-structured with proper use of the enabled parameter for conditional clickability, consistent theming, and appropriate layout.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt (2)

136-139: LGTM!

The action handler correctly maps OnGroupClick to NavigateToGroupDetails event, following the established pattern in this ViewModel.


175-176: LGTM!

The new event and action classes are properly defined with groupId: Int, consistent with the backend API type. Based on learnings, groupId is intentionally typed as Int in this codebase.

Also applies to: 193-194

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileScreen.kt (2)

60-60: LGTM!

The navigateToGroupDetails callback parameter is correctly added to the screen signature.


106-109: LGTM!

Event handling for NavigateToGroupDetails correctly invokes the navigation callback with the event's groupId.

core/network/src/commonMain/kotlin/com/mifos/core/network/mappers/clients/ClientMapper.kt (1)

31-32: LGTM! Clean bidirectional mapping for group fields.

The mapper correctly handles the new groupId and groupName fields in both directions, maintaining nullable types and following the existing pattern. The placement after office-related fields is logical.

Also applies to: 58-59

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

48-52: LGTM! Inline comment clarifies intentional type choice.

The new fields are correctly implemented with appropriate nullable types and defaults. The inline comment on line 48 usefully documents why groupId is Int? rather than Long? like other ID fields, aligning with the backend API contract.

Based on learnings, the groupId type is intentionally Int? per the backend API specification.

Comment on lines 197 to 199
navigateToGroupDetails = { groupId ->
navController.navigateToGroupDetailsScreen(groupId)
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

LGTM, but here use navigateToGroupDetails = navController::navigateToGroupDetailsScreen instead,

Comment on lines 88 to 89
// The API returns a list of groups but the UI requires a single Group Name.
// we default to using the first group in the list as the primary identifier.
Copy link
Contributor

Choose a reason for hiding this comment

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

Have you verified this listing of only the first group with the web-app?

Copy link
Contributor

Choose a reason for hiding this comment

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

@kartikey004 Have you confirmed this with the web-app, if only the first group is displayed if a client is associated with multiple groups?


val officeName: String? = null,

// backend returns groupId as an Int here
Copy link
Contributor

@biplab1 biplab1 Jan 8, 2026

Choose a reason for hiding this comment

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

Please avoid such comments unless very important. Also, consider removing them if used elsewhere in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@biplab1 I initially did not have this comment. I added it only after the bot raised a major issue and suggested clarifying it in multiple review comments. If you feel it’s unnecessary, I can remove it.

Copy link
Contributor

@biplab1 biplab1 left a comment

Choose a reason for hiding this comment

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

Looks good to me. This can be merged.

color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.8f),
)

Spacer(Modifier.height(DesignToken.padding.small))
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please replace DesignToken.padding with KptTheme.spacing where it can be done following this table: openMF/mifos-mobile#3013 (comment)

Always prefer KptTheme over DesignToken wherever possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@biplab1 I don't think KptTheme is implemented in the android-client yet. I checked the project and only MifosTheme and DesignToken are available right now.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt (1)

96-108: Code looks functionally correct; minor simplification possible.

The enrichment logic correctly populates groupName and groupId from the first group when groupName is blank. However, the null-safe operators inside the if block are redundant since the condition already guarantees groups is non-null and non-empty.

♻️ Optional: Simplify redundant null checks
 override suspend fun getClient(clientId: Int): ClientEntity {
     val client = dataManagerClient.getClient(clientId)

-    if (client.groupName.isNullOrBlank() && !client.groups.isNullOrEmpty()) {
-        client.groups?.firstOrNull()?.let { firstGroup ->
-            return client.copy(
-                groupName = firstGroup.name,
-                groupId = firstGroup.id,
-            )
-        }
+    if (client.groupName.isNullOrBlank()) {
+        client.groups?.firstOrNull()?.let { firstGroup ->
+            return client.copy(
+                groupName = firstGroup.name,
+                groupId = firstGroup.id,
+            )
+        }
     }
     return client
 }

This version relies on firstOrNull() returning null for empty/null lists, eliminating the explicit isNullOrEmpty() check while preserving the same behavior.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 198922c and aed71cc.

📒 Files selected for processing (3)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt
  • feature/client/src/commonMain/composeResources/values/strings.xml
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • feature/client/src/commonMain/composeResources/values/strings.xml
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientProfile/ClientProfileViewModel.kt
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-08T13:21:12.300Z
Learnt from: kartikey004
Repo: openMF/android-client PR: 2571
File: core/network/src/commonMain/kotlin/com/mifos/core/network/model/GetClientsPageItemsResponse.kt:48-48
Timestamp: 2026-01-08T13:21:12.300Z
Learning: In the android-client codebase, the groupId field in GetClientsPageItemsResponse is intentionally typed as Int? (not Long?) because the backend API explicitly returns groupId as an Int, even though other ID fields like id and officeId use Long?.

Applied to files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/ClientDetailsRepositoryImp.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR Checks / Static Analysis Check

@therajanmaurya therajanmaurya merged commit f384d91 into openMF:development Jan 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants