Skip to content

fix(history): Fetch transactions only for selected account#1953

Merged
therajanmaurya merged 1 commit intoopenMF:developmentfrom
sahilshivekar:feature/mw-326-transactions-clean-up
Mar 2, 2026
Merged

fix(history): Fetch transactions only for selected account#1953
therajanmaurya merged 1 commit intoopenMF:developmentfrom
sahilshivekar:feature/mw-326-transactions-clean-up

Conversation

@sahilshivekar
Copy link
Contributor

@sahilshivekar sahilshivekar commented Jan 19, 2026

Jira Task: MW-326

Description

Before HistoryViewModel was fetching transactions for all the accounts initially.
Now it fetches transactions only for the selected account.
Behavior of the app on screen doesn't change.
Second savings account of user have 4 transactions on 28 feb 2026. (first savings account have no transactions on 28 feb 2026)

Screen recording

Before

Those 4 transactions of not selected account are fetched initially.

mw-326-old.mp4

After

Those 4 transactions of not selected account are fetched after selecting that account.

mw-326-new.mp4

Summary by CodeRabbit

  • Refactor

    • History now loads accounts first, then transactions for the selected account; filtering simplified.
  • UI / Behavior

    • Header, filter sheet, and list/empty detection reflect selected account and selected transaction type.
    • Error state shows dynamic, context-aware messages.
  • Bug Fixes

    • Shows "No accounts found" when there are no accounts.
  • Chores

    • Reduced public surface: removed an account/transactions API.

@coderabbitai
Copy link

coderabbitai bot commented Jan 19, 2026

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

Removed the combined accounts-with-transactions repository API; refactored History to load accounts then transactions sequentially, renamed SetFilter → SetTransactionType, simplified History state and UI bindings, and added a "No accounts found" string resource.

Changes

Cohort / File(s) Summary
Repository API Removal
core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt, core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImpl/SelfServiceRepositoryImpl.kt
Deleted getActiveAccountsWithTransactions(clientId: Long, limit: Int) API and its implementation; removed AccountsWithTransactions import.
History UI bindings
feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryScreen.kt
Switched error subtitle to state.viewState.message; bound selectedTransactionType and selectedAccount from state; emptiness check uses state.viewState.list.isEmpty(); dispatches HistoryAction.SetTransactionType; removed unused imports.
HistoryViewModel refactor
feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt
Made repository private; added loadActiveAccounts() and loadTransactions(accountId) flows; removed TransactionsLoaded and legacy multi-account fields; renamed SetFilterSetTransactionType; state reshaped to include accounts, transactions, selectedAccount, selectedTransactionType; error viewState now uses StringResource.
Resources
feature/history/src/commonMain/composeResources/values/strings.xml
Added feature_history_no_account string resource ("No accounts found").

Sequence Diagram

sequenceDiagram
    participant UI as HistoryScreen
    participant VM as HistoryViewModel
    participant Repo as SelfServiceRepository
    participant State as StateStore

    UI->>VM: Init
    note over VM: init -> loadActiveAccounts()
    VM->>Repo: getActiveAccounts(clientId)
    Repo-->>VM: DataState<List<Account>>
    VM->>State: update accounts, set selectedAccount

    alt accounts exist
        VM->>Repo: getTransactions(accountId)
        Repo-->>VM: DataState<List<Transaction>>
        VM->>VM: apply selectedTransactionType filter
        VM->>State: update viewState with filtered transactions
    else no accounts
        VM->>State: emit viewState Error (feature_history_no_account)
    end

    UI->>VM: HistoryAction.SetTransactionType / SetSelectedAccount / ApplyFilter
    VM->>VM: decide reload vs local filter
    VM->>State: emit updated ViewState
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hopped through code with nimble feet,

Split accounts and transactions neat.
Filters renamed, the state trimmed fine,
No accounts found — a friendly sign.
🥕

🚥 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
Title check ✅ Passed The title 'fix(history): Fetch transactions only for selected account' directly summarizes the main change in the PR, which is refactoring the HistoryViewModel to load transactions only for the selected account instead of all accounts.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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: 4

Caution

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

⚠️ Outside diff range comments (1)
feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt (1)

151-164: Unfiltered empty list should surface ViewState.Empty.

applyFilter always emits Content, even when the base list is empty and no filter is applied. That forces the UI into the “filtered empty” copy for a “no transactions yet” case. Consider emitting Empty when filter == OTHER and the list is empty.

💡 Proposed refinement
-        mutableStateFlow.update {
-            it.copy(
-                viewState = HistoryState.ViewState.Content(filteredTransactions),
-            )
-        }
+        mutableStateFlow.update {
+            it.copy(
+                viewState = if (filteredTransactions.isEmpty() && filter == TransactionType.OTHER) {
+                    HistoryState.ViewState.Empty
+                } else {
+                    HistoryState.ViewState.Content(filteredTransactions)
+                },
+            )
+        }
🤖 Fix all issues with AI agents
In
`@feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt`:
- Around line 59-77: The DataState.Error branch should not map to
HistoryState.ViewState.Empty while leaving prior transactions in state; update
the is DataState.Error case in mutableStateFlow.update to clear the transactions
(set transactions = emptyList()) and emit an error view state (e.g.,
HistoryState.ViewState.Error with the error/exception from the DataState
instance) instead of HistoryState.ViewState.Empty so stale data is removed and
the UI can surface the failure.
- Around line 117-126: The current logic in HistoryViewModel skips handling when
state.transactions is empty, so switching to an account with zero previously
loaded transactions never triggers loadTransactions; change the branch to always
attempt to load transactions for the currently selected account unless the
existing transactions are non-empty and already belong to that account—i.e., in
the block referencing state.transactions, state.currentSelectedAccount,
applyFilter, and loadTransactions, replace the guard that checks only
state.transactions.isNotEmpty() with logic that checks whether
state.transactions is non-empty AND the first transaction's accountId equals
state.currentSelectedAccount?.id (then call applyFilter), otherwise call
loadTransactions(state.currentSelectedAccount!!.id) when a
currentSelectedAccount exists.
- Around line 85-99: The loadActiveAccountsAndInitialTransactions function
currently only handles the Success case from repository.getActiveAccounts and
leaves mutableStateFlow unchanged on Error or empty results; update the
collector on repository.getActiveAccounts(state.clientId) to explicitly handle
all Resource states (e.g., Loading, Success, Error) and update mutableStateFlow
accordingly (set a loading flag on Loading, set an error state/message on
Error), and when Success contains an empty list emit an Empty/appropriate state
instead of leaving the UI stuck; ensure you still call
loadTransactions(accountId) only when a non-empty accounts list exists and use
viewModelScope.launchIn as before.
- Around line 82-83: The loadTransactions flow can produce stale updates when
multiple calls run concurrently; in HistoryViewModel, introduce a Job property
(e.g., private var loadJob: Job? = null) and in the function that calls
loadTransactions cancel loadJob?.cancel() before launching the new collector
with viewModelScope and assign the returned Job to loadJob, and additionally,
before applying any result to state verify it matches the current selection
(e.g., compare result.accountId to the ViewModel's
currentSelection/currentlySelectedAccountId) so late emissions are ignored;
update loadTransactions callers (the sites from which it is invoked) to rely on
this guarded/canceling behavior.

@sahilshivekar sahilshivekar force-pushed the feature/mw-326-transactions-clean-up branch from b2fb02b to 691faea Compare January 19, 2026 15:53
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 `@feature/history/src/commonMain/composeResources/values/strings.xml`:
- Line 26: The string resource feature_history_no_account currently contains
literal quotation marks; remove the surrounding double quotes from the value so
it reads No accounts found (i.e., update the <string
name="feature_history_no_account"> entry to contain the plain text without
enclosing " characters) to match other strings and prevent quotes from appearing
in the UI.

In
`@feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt`:
- Around line 75-84: In HistoryViewModel's success branch, replace the call to
applyFilter(state.transactions) with applyFilter(transactions) so the freshly
received local variable is used; locate the block updating mutableStateFlow with
HistoryState.ViewState.Content(transactions) and pass the local transactions
variable to applyFilter to avoid reading from state after the update.
🧹 Nitpick comments (2)
feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt (2)

63-67: Consider clearing transactions on error to avoid stale data.

The error handling now correctly emits an error state (addressing the previous concern). However, the transactions list isn't cleared, meaning stale data from a previous account could resurface if the user switches back or retries. Consider clearing transactions when an error occurs.

Proposed fix
                 is DataState.Error -> {
                     mutableStateFlow.update {
-                        it.copy(viewState = HistoryState.ViewState.Error(Res.string.feature_history_error))
+                        it.copy(
+                            transactions = emptyList(),
+                            viewState = HistoryState.ViewState.Error(Res.string.feature_history_error),
+                        )
                     }
                 }

113-128: Update state before triggering transaction load for consistent ordering.

Currently, loadTransactions is called before updating the state with accounts and selectedAccount. While this works because loadTransactions runs asynchronously, updating the state first provides clearer data flow and ensures selectedAccount is set if any synchronous access occurs.

Proposed reordering
                 is DataState.Success -> {
                     val accounts = result.data
                     if (accounts.isNotEmpty()) {
-                        loadTransactions(accounts.first().id)
                         mutableStateFlow.update { state ->
                             state.copy(
                                 accounts = accounts,
                                 selectedAccount = accounts.firstOrNull(),
                             )
                         }
+                        loadTransactions(accounts.first().id)
                     } else {

@sahilshivekar sahilshivekar force-pushed the feature/mw-326-transactions-clean-up branch from 35d8930 to 56dac72 Compare January 19, 2026 16:27
@biplab1
Copy link
Contributor

biplab1 commented Feb 13, 2026

@sahilshivekar Since it is a refactor, please add a screen recording to ensure there are no regressions.

@sahilshivekar sahilshivekar force-pushed the feature/mw-326-transactions-clean-up branch from 56dac72 to 74b2623 Compare February 19, 2026 09:31
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.

🧹 Nitpick comments (2)
feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt (2)

75-84: Redundant intermediate Content emission before applyFilter.

Lines 78–83 write Content(transactions) (unfiltered), and applyFilter on line 84 immediately overwrites it with Content(filteredTransactions). When selectedTransactionType != OTHER, this produces an unnecessary state emission that briefly exposes unfiltered data. Removing the viewState assignment from the first update and relying solely on applyFilter eliminates the redundancy.

♻️ Proposed fix
 is DataState.Success -> {
     val transactions = result.data
     if (transactions.isNotEmpty()) {
         mutableStateFlow.update {
             it.copy(
                 transactions = transactions,
-                viewState = HistoryState.ViewState.Content(transactions),
             )
         }
         applyFilter(transactions)
     } else {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt`
around lines 75 - 84, Remove the redundant unfiltered Content emission by
updating the mutableStateFlow only with transactions (not viewState) before
calling applyFilter; specifically, in the DataState.Success branch where
result.data is assigned to transactions, stop setting viewState =
HistoryState.ViewState.Content(transactions) in that first
mutableStateFlow.update and instead let applyFilter(transactions) compute and
set the proper HistoryState.ViewState.Content (filtered) based on
selectedTransactionType, so only the final filtered state is emitted.

123-127: ViewState.Error is semantically incorrect for "no accounts found."

An empty account list is an informational/empty condition, not an error. Reusing ViewState.Error for it means the UI will render the error UI (e.g. "Oops!") rather than a neutral empty message, which degrades UX. Consider adding a message parameter to ViewState.Empty, or introducing a dedicated ViewState.NoAccounts variant.

♻️ Proposed alternative
-data object Empty : ViewState
+data class Empty(val message: StringResource? = null) : ViewState

Then in loadActiveAccounts:

-mutableStateFlow.update {
-    it.copy(viewState = HistoryState.ViewState.Error(Res.string.feature_history_no_account))
-}
+mutableStateFlow.update {
+    it.copy(viewState = HistoryState.ViewState.Empty(Res.string.feature_history_no_account))
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt`
around lines 123 - 127, The code sets ViewState.Error for the "no accounts"
condition which is semantically wrong; update the ViewState model and the
HistoryViewModel logic so the UI shows a neutral empty state: either (A) add an
optional message parameter to ViewState.Empty (e.g., Empty(message: String?))
and set viewState =
HistoryState.ViewState.Empty(Res.string.feature_history_no_account), or (B)
introduce a dedicated variant ViewState.NoAccounts (or NoItems) and set
viewState = HistoryState.ViewState.NoAccounts when loadActiveAccounts finds zero
accounts; then replace the mutableStateFlow.update call that currently sets
ViewState.Error with the new Empty(message) or NoAccounts variant and update any
UI consumers to handle the new variant.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt`:
- Around line 63-67: The Error branch in HistoryViewModel currently sets
viewState to HistoryState.ViewState.Error but leaves stale state.transactions
intact; update the is DataState.Error handling in HistoryViewModel (the
mutableStateFlow.update call) to also clear or set transactions = emptyList()
(and any related filtered lists) so subsequent handleApplyFilterClick, which
reads state.transactions, won’t re-apply stale data; ensure the
mutableStateFlow.update modifies the state object to reset transactions before
setting viewState to HistoryState.ViewState.Error.

---

Nitpick comments:
In
`@feature/history/src/commonMain/kotlin/org/mifospay/feature/history/HistoryViewModel.kt`:
- Around line 75-84: Remove the redundant unfiltered Content emission by
updating the mutableStateFlow only with transactions (not viewState) before
calling applyFilter; specifically, in the DataState.Success branch where
result.data is assigned to transactions, stop setting viewState =
HistoryState.ViewState.Content(transactions) in that first
mutableStateFlow.update and instead let applyFilter(transactions) compute and
set the proper HistoryState.ViewState.Content (filtered) based on
selectedTransactionType, so only the final filtered state is emitted.
- Around line 123-127: The code sets ViewState.Error for the "no accounts"
condition which is semantically wrong; update the ViewState model and the
HistoryViewModel logic so the UI shows a neutral empty state: either (A) add an
optional message parameter to ViewState.Empty (e.g., Empty(message: String?))
and set viewState =
HistoryState.ViewState.Empty(Res.string.feature_history_no_account), or (B)
introduce a dedicated variant ViewState.NoAccounts (or NoItems) and set
viewState = HistoryState.ViewState.NoAccounts when loadActiveAccounts finds zero
accounts; then replace the mutableStateFlow.update call that currently sets
ViewState.Error with the new Empty(message) or NoAccounts variant and update any
UI consumers to handle the new variant.

@sahilshivekar sahilshivekar changed the title fix(history): Fetch transactions only for selected account (MW-326) fix(history): Fetch transactions only for selected account Feb 19, 2026
Copy link
Contributor

@revanthkumarJ revanthkumarJ 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 see if we can add another account and show in video how it works when user changes account from drop down

@sahilshivekar
Copy link
Contributor Author

looks good to me see if we can add another account and show in video how it works when user changes account from drop down

@revanthkumarJ I have uploaded new videos with description and logs as a proof since nothing changes on UI.

@sahilshivekar sahilshivekar force-pushed the feature/mw-326-transactions-clean-up branch 2 times, most recently from 8964877 to 8a5a0d1 Compare February 28, 2026 22:40
Copy link
Contributor

@revanthkumarJ revanthkumarJ left a comment

Choose a reason for hiding this comment

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

fix static checks remaining fine

@sahilshivekar
Copy link
Contributor Author

fix static checks remaining fine

@revanthkumarJ Something is going wrong, check this https://mifos.slack.com/archives/C5TTJS4BX/p1772353496479949?thread_ts=1768831891.339249&cid=C5TTJS4BX

@sahilshivekar sahilshivekar force-pushed the feature/mw-326-transactions-clean-up branch from 90ba43f to 18b842f Compare March 2, 2026 08:54
@therajanmaurya therajanmaurya merged commit 14cd524 into openMF:development Mar 2, 2026
8 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.

4 participants