Skip to content

fix: split mileage page observables to two parts to improve loading time#4140

Open
arjunaj5 wants to merge 2 commits intomasterfrom
Fyle-add-edit-mileage-loader-fix
Open

fix: split mileage page observables to two parts to improve loading time#4140
arjunaj5 wants to merge 2 commits intomasterfrom
Fyle-add-edit-mileage-loader-fix

Conversation

@arjunaj5
Copy link
Contributor

@arjunaj5 arjunaj5 commented Mar 13, 2026

Clickup

https://app.clickup.com

Code Coverage

Please add code coverage here

UI Preview

Please add screenshots for UI changes

Summary by CodeRabbit

  • Performance
    • The mileage form now loads faster, showing core fields immediately while secondary data loads in the background.
  • New Features
    • Improved progressive loading so initial values appear sooner and remaining details populate shortly after.
    • Smarter autofill that more reliably selects recent projects, cost centers, and reports once secondary data arrives.
  • Bug Fixes
    • Stabilized form state and field updates to reduce flicker and incorrect temporary selections.

@arjunaj5 arjunaj5 requested a review from Chethan-Fyle as a code owner March 13, 2026 07:08
@arjunaj5 arjunaj5 requested a review from mvaishnavi March 13, 2026 07:09
@github-actions github-actions bot added the size/M Medium PR label Mar 13, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: dfbbb903-7a16-417d-83e1-fb496464c052

📥 Commits

Reviewing files that changed from the base of the PR and between 766b5d3 and d4c0aae.

📒 Files selected for processing (1)
  • src/app/fyle/add-edit-mileage/add-edit-mileage.page.setup.spec.ts

Walkthrough

Iyar, the mileage add-edit flow is split into two sequential fetch phases: Phase 1 loads critical data to render the form quickly; Phase 2 loads secondary data (projects, reports, recent values, commute details) and patches dependent fields afterwards.

Changes

Cohort / File(s) Summary
Test file (format-only)
src/app/fyle/add-edit-mileage/add-edit-mileage.page.setup.spec.ts
Whitespace/formatting change at EOF; no logic or test behavior altered.
Add/Edit Mileage page
src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts
Introduces two-phase data loading: Phase 1 fetches critical data (etxn, subCategory, txnFields, customExpenseFields, allMileageRates, defaultPaymentMode, orgSettings) and patches initial form values; Phase 2 fetches secondary data (project, report, costCenter, recentValue, recentProjects, recentCostCenters, commuteDeductionDetails, employeeSettings, orgSettings) to update autofill, dependent fields, and commute details. Adjusts patching to avoid UI instability, defers slower API data, and removes initialFetch public property.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I strike fast, Phase One — form appears, crisp and bright,
Phase Two follows like thunder, filling in the night.
Projects and reports bow down, fields fall into place,
Mileage flows like cinema — smooth, swift, full of grace. ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description follows the required template structure but contains placeholder text ('Please add code coverage here' and 'Please add screenshots for UI changes') instead of actual content. Replace placeholder text with actual code coverage metrics and UI preview screenshots. Ensure the ClickUp link points to the actual task, not a generic URL.
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 (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: splitting mileage page observables into two parts to improve loading time, which matches the core objective.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Fyle-add-edit-mileage-loader-fix
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@github-actions
Copy link

Unit Test Coverage % values
Statements 14.62% ( 3299 / 22557 )
Branches 7.68% ( 670 / 8715 )
Functions 5.51% ( 366 / 6639 )
Lines 14.29% ( 3122 / 21833 )

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/app/fyle/add-edit-mileage/add-edit-mileage.page.setup.spec.ts`:
- Line 70: The test suite is using fdescribe('AddEditMileagePage', ...) which
forces only this spec to run; change fdescribe to describe in the
AddEditMileagePage spec (replace fdescribe('AddEditMileagePage', ...) with
describe('AddEditMileagePage', ...)) so the full test suite runs again and
re-run tests to confirm no other focused specs remain.

In `@src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts`:
- Around line 2087-2095: The final fg.patchValue is overwriting the freshly
autofilled costCenter with the stale/older costCenter variable; change the patch
logic in add-edit-mileage.page.ts so it uses the computed autoFillCostCenter
(and this.presetCostCenterId) when present instead of the older costCenter local
variable—mirror the effectiveProject pattern: derive an effectiveCostCenter
(prefer autoFillCostCenter.value, fall back to existing fg.value.costCenter) and
patch that into fg and presetCostCenterId so the UI and dependent fields aren't
reset to null.
- Around line 2004-2017: The forkJoin combining observables (forkJoin({ etxn:
this.etxn$, project: selectedProject$, report: selectedReport$, costCenter:
selectedCostCenter$, recentValue: this.recentlyUsedValues$, recentProjects:
this.recentlyUsedProjects$, recentCostCenters: this.recentlyUsedCostCenters$,
commuteDeductionDetails: commuteDeductionDetails$, employeeSettings:
employeeSettings$, orgSettings: orgSettings$ })) is brittle because any source
error will fail the whole join; update the non-critical sources (all except
this.etxn$) by piping them through catchError and returning safe fallbacks
(e.g., [] for lists, null for optional objects) before passing into forkJoin so
secondary hydration survives individual failures while keeping etxn as the
required source.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: dde3a6dc-f2c4-44bc-b4b5-533d417b2a43

📥 Commits

Reviewing files that changed from the base of the PR and between 43eef17 and 766b5d3.

📒 Files selected for processing (2)
  • src/app/fyle/add-edit-mileage/add-edit-mileage.page.setup.spec.ts
  • src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts

Comment on lines +2004 to +2017
forkJoin({
etxn: this.etxn$,
project: selectedProject$,
report: selectedReport$,
costCenter: selectedCostCenter$,
recentValue: this.recentlyUsedValues$,
recentProjects: this.recentlyUsedProjects$,
recentCostCenters: this.recentlyUsedCostCenters$,
commuteDeductionDetails: commuteDeductionDetails$,
employeeSettings: employeeSettings$,
orgSettings: orgSettings$,
})
.pipe(take(1))
.subscribe(
Copy link

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

🌐 Web query:

In RxJS, does forkJoin fail the whole combined observable if any inner observable errors before completion?

💡 Result:

Yes. forkJoin errors the combined observable if any inner/source observable errors, and it immediately unsubscribes from the other inner observables (so you won’t get a final combined value). [1]

If you want the join to still succeed when one source fails, you must handle errors inside each inner observable (e.g., with catchError returning a fallback value) before passing them to forkJoin. [1]

Sources:
[1] RxJS source/docs comment for forkJoin (ReactiveX/rxjs) (raw.githubusercontent.com)

Citations:


🏁 Script executed:

cd src/app/fyle/add-edit-mileage && wc -l add-edit-mileage.page.ts

Repository: fylein/fyle-mobile-app

Length of output: 95


🏁 Script executed:

sed -n '1980,2050p' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts | cat -n

Repository: fylein/fyle-mobile-app

Length of output: 2986


🏁 Script executed:

# Search for error handling patterns in this file
rg 'catchError|try|catch' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts -B 2 -A 2 | head -100

Repository: fylein/fyle-mobile-app

Length of output: 888


🏁 Script executed:

# Check how the forkJoin result is consumed
sed -n '2015,2100p' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts | cat -n

Repository: fylein/fyle-mobile-app

Length of output: 4054


🏁 Script executed:

# Find where selectedProject$ and other observables are created/defined
rg 'selectedProject\$|selectedReport\$|selectedCostCenter\$' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts -B 3 -A 3

Repository: fylein/fyle-mobile-app

Length of output: 2200


🏁 Script executed:

# Search for recentlyUsedValues$, recentlyUsedProjects$, recentlyUsedCostCenters$
rg 'recentlyUsedValues\$|recentlyUsedProjects\$|recentlyUsedCostCenters\$' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts -B 3 -A 3

Repository: fylein/fyle-mobile-app

Length of output: 2615


🏁 Script executed:

# Search for commuteDeductionDetails$, employeeSettings$, orgSettings$ creation
rg 'commuteDeductionDetails\$|employeeSettings\$|orgSettings\$' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts -B 3 -A 3 | head -80

Repository: fylein/fyle-mobile-app

Length of output: 2742


🏁 Script executed:

# Check the full scope of the ngOnInit or initialization method to see observable creation
rg 'ngOnInit|this\.etxn\$ =' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts -A 30 | head -150

Repository: fylein/fyle-mobile-app

Length of output: 3792


🏁 Script executed:

# Check if Phase 2 forkJoin has error handling in the subscribe call
sed -n '2000,2100p' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts | cat -n

Repository: fylein/fyle-mobile-app

Length of output: 4763


🏁 Script executed:

# Check the complete subscribe signature - look for error handler
sed -n '2000,2150p' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts | grep -A 100 'forkJoin' | head -150

Repository: fylein/fyle-mobile-app

Length of output: 4103


🏁 Script executed:

# Find where the subscribe call ends to see if there's an error handler
sed -n '2017,2200p' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts | tail -80

Repository: fylein/fyle-mobile-app

Length of output: 2410


🏁 Script executed:

# Find the exact subscribe pattern - look for closing of subscribe with potential error handler
sed -n '2017,2130p' src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts | tail -50

Repository: fylein/fyle-mobile-app

Length of output: 2122


Phase 2 forkJoin is a thunderbolt waiting to strike—one slow or erroring observable pulls down the entire secondary hydration.

RxJS forkJoin fails the combined observable if ANY source errors before completion. Your Phase 2 has no error handler, and you're joining 10 sources (three of them are nested forkJoin calls themselves). When one breaks—network timeout, service unavailable, whatever the heavens decree—the entire chain collapses. Projects, reports, cost centers, recent values: all vanish. The form appears but remains a skeleton.

For non-critical data like dropdowns and autofills, this all-or-nothing behavior is a weakness. Wrap the non-critical observables with catchError, returning fallback values (empty arrays for lists, null for objects), so the secondary data hydrates gracefully even when individual sources fail. Let etxn stand firm—it's the foundation. But the rest? They can fail alone without toppling the temple.

🛠️ Suggested resilience pattern
+    const safe = <T>(obs$: Observable<T>, fallback: T): Observable<T> =>
+      obs$.pipe(catchError(() => of(fallback)));
+
     forkJoin({
-      etxn: this.etxn$,
-      project: selectedProject$,
-      report: selectedReport$,
-      costCenter: selectedCostCenter$,
-      recentValue: this.recentlyUsedValues$,
-      recentProjects: this.recentlyUsedProjects$,
-      recentCostCenters: this.recentlyUsedCostCenters$,
-      commuteDeductionDetails: commuteDeductionDetails$,
-      employeeSettings: employeeSettings$,
-      orgSettings: orgSettings$,
+      etxn: safe(this.etxn$, null),
+      project: safe(selectedProject$, null),
+      report: safe(selectedReport$, null),
+      costCenter: safe(selectedCostCenter$, null),
+      recentValue: safe(this.recentlyUsedValues$, null),
+      recentProjects: safe(this.recentlyUsedProjects$, []),
+      recentCostCenters: safe(this.recentlyUsedCostCenters$, []),
+      commuteDeductionDetails: safe(commuteDeductionDetails$, null),
+      employeeSettings: safe(employeeSettings$, null),
+      orgSettings: safe(orgSettings$, null),
     })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts` around lines 2004 -
2017, The forkJoin combining observables (forkJoin({ etxn: this.etxn$, project:
selectedProject$, report: selectedReport$, costCenter: selectedCostCenter$,
recentValue: this.recentlyUsedValues$, recentProjects:
this.recentlyUsedProjects$, recentCostCenters: this.recentlyUsedCostCenters$,
commuteDeductionDetails: commuteDeductionDetails$, employeeSettings:
employeeSettings$, orgSettings: orgSettings$ })) is brittle because any source
error will fail the whole join; update the non-critical sources (all except
this.etxn$) by piping them through catchError and returning safe fallbacks
(e.g., [] for lists, null for optional objects) before passing into forkJoin so
secondary hydration survives individual failures while keeping etxn as the
required source.

Comment on lines 2087 to 2095
if (
doRecentCostCenterIdsExist &&
(!etxn.tx.id || (etxn.tx.id && etxn.tx.state === 'DRAFT' && !etxn.tx.cost_center_id))
) {
const autoFillCostCenter = recentCostCenters && recentCostCenters.length > 0 && recentCostCenters[0];

if (autoFillCostCenter) {
costCenter = autoFillCostCenter.value;
this.presetCostCenterId = autoFillCostCenter.value.id;
this.fg.patchValue({ costCenter });
this.fg.patchValue({ costCenter: autoFillCostCenter.value });
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Line 2108 can undo cost-center autofill done at Line 2094.

You compute and patch autofilled costCenter, then final patch uses the older costCenter variable and can reset it (often to null). This can desync UI state and dependent fields.

🛠️ Suggested fix (mirror `effectiveProject` pattern)
+          let effectiveCostCenter = costCenter;
           if (
             doRecentCostCenterIdsExist &&
             (!etxn.tx.id || (etxn.tx.id && etxn.tx.state === 'DRAFT' && !etxn.tx.cost_center_id))
           ) {
             const autoFillCostCenter = recentCostCenters && recentCostCenters.length > 0 && recentCostCenters[0];
             if (autoFillCostCenter) {
               this.presetCostCenterId = autoFillCostCenter.value.id;
-              this.fg.patchValue({ costCenter: autoFillCostCenter.value });
+              effectiveCostCenter = autoFillCostCenter.value;
+              this.fg.patchValue({ costCenter: effectiveCostCenter });
             }
           }

-          this.fg.patchValue({ report, costCenter, project: effectiveProject ?? project }, { emitEvent: false });
+          this.fg.patchValue(
+            { report, costCenter: effectiveCostCenter ?? costCenter, project: effectiveProject ?? project },
+            { emitEvent: false },
+          );

Also applies to: 2108-2108

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

In `@src/app/fyle/add-edit-mileage/add-edit-mileage.page.ts` around lines 2087 -
2095, The final fg.patchValue is overwriting the freshly autofilled costCenter
with the stale/older costCenter variable; change the patch logic in
add-edit-mileage.page.ts so it uses the computed autoFillCostCenter (and
this.presetCostCenterId) when present instead of the older costCenter local
variable—mirror the effectiveProject pattern: derive an effectiveCostCenter
(prefer autoFillCostCenter.value, fall back to existing fg.value.costCenter) and
patch that into fg and presetCostCenterId so the UI and dependent fields aren't
reset to null.

@github-actions
Copy link

🔁 Code Duplication Report - Angular

Format Files analyzed Total lines Total tokens Clones found Duplicated lines Duplicated tokens
java 4 196 1457 0 0 (0.00%) 0 (0.00%)
typescript 756 58117 501157 210 2855 (4.91%) 26139 (5.22%)
scss 192 21746 116360 112 3935 (18.10%) 21209 (18.23%)
markup 294 19823 166326 107 1439 (7.26%) 11970 (7.20%)
python 4 697 5373 3 32 (4.59%) 368 (6.85%)
css 1 38 219 0 0 (0.00%) 0 (0.00%)
swift 1 105 836 0 0 (0.00%) 0 (0.00%)
properties 2 29 73 0 0 (0.00%) 0 (0.00%)
javascript 16 1024 7043 1 10 (0.98%) 108 (1.53%)
prolog 1 60 559 0 0 (0.00%) 0 (0.00%)
groovy 6 192 1152 0 0 (0.00%) 0 (0.00%)
yaml 14 618 4561 9 187 (30.26%) 1554 (34.07%)
markdown 2 274 2046 0 0 (0.00%) 0 (0.00%)
bash 1 12 83 0 0 (0.00%) 0 (0.00%)
Total: 1294 102931 807245 442 8458 (8.22%) 61348 (7.60%)

📊 No significant change in code duplication.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Medium PR

Development

Successfully merging this pull request may close these issues.

2 participants