Skip to content

Fix slow iOS loading across mobile pages - #1471

Merged
Asherlc merged 5 commits into
mainfrom
Asherlc/issue-1429
Jul 3, 2026
Merged

Asherlc merged 5 commits into
mainfrom
Asherlc/issue-1429

Conversation

@Asherlc

@Asherlc Asherlc commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • keep Today and Strain cached data visible during background refreshes
  • add focused tests for non-blocking cached mobile loading states
  • scope pull-to-refresh invalidation on high-traffic mobile and provider screens

Verification

  • rtk pnpm vitest run packages/server/src/routers/sync.test.ts --testNamePattern dataHealth --project unit
  • rtk pnpm vitest run packages/mobile/lib/loading-policy.test.ts packages/mobile/lib/mobile-query-persistence.test.tsx packages/mobile/app/_layout.test.ts packages/mobile/app/_layout.cleanup.test.tsx --project mobile
  • rtk pnpm vitest run packages/mobile/app/(tabs)/activities.test.tsx packages/mobile/app/(tabs)/food.test.tsx packages/mobile/app/providers/index.test.tsx packages/mobile/app/providers/[id].test.tsx packages/mobile/app/(tabs)/strain.test.tsx packages/mobile/app/(tabs)/index.test.tsx --project mobile
  • rtk pnpm test:mobile
  • rtk env DBT_CLICKHOUSE_HOST=127.0.0.1 DBT_CLICKHOUSE_PORT=55000 DBT_CLICKHOUSE_USER=default DBT_CLICKHOUSE_PASSWORD=health pnpm lint
  • rtk pnpm typecheck
  • rtk pnpm --dir packages/mobile typecheck
  • rtk pnpm --dir packages/server typecheck
  • rtk pnpm --dir packages/web typecheck

Fixes #1429


Summary by cubic

Improve iOS load times by keeping cached content visible during background refreshes and tightening pull-to-refresh scopes. Prevents skeleton flicker on Today and Strain, adds an inline loader for Strain activities, and speeds up refresh on Providers, Activities, and Food. Fixes #1429.

  • Bug Fixes
    • Keep cached data visible while refreshing on Today and Strain; show a non-blocking dashboard error on Today when a refresh fails; add an inline loader for Strain activities.
    • Scope pull-to-refresh invalidation: Activities (week list, activity overview, activity list, data health), Food (food by date, calorie goal), Providers (providers, provider stats, logs [limit 50], data health, active syncs), Provider Detail (records, logs, providers list, provider stats, data health).
    • Add tests for cached non-blocking loading on Today and Strain, background refresh error on Today, and scoped refresh on Food, Providers, and Provider Detail.

Written for commit 1bf6179. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Pull-to-refresh now updates more screens with targeted data refreshes, including activities, food, providers, and provider details.
    • The Today and Strain screens now keep previously loaded content visible while data is refreshing.
  • Bug Fixes

    • Improved loading behavior so cached dashboard and training data no longer gets replaced by a blocking loading state during refresh.
    • Refresh actions now better stay in sync with related data, reducing stale information after pull-to-refresh.

Copilot AI review requested due to automatic review settings July 3, 2026 15:56
@Asherlc Asherlc linked an issue Jul 3, 2026 that may be closed by this pull request
6 tasks
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry @Asherlc, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Mobile pull-to-refresh flows on activities, food, provider detail, and providers list screens now perform targeted tRPC query invalidation via trpcUtils instead of default useRefresh() behavior. Today and Strain screens use shouldShowBlockingLoading with isFetching and placeholderData to keep cached content visible during background refetches. Tests updated accordingly.

Changes

Targeted pull-to-refresh invalidation

Layer / File(s) Summary
Activities refresh scoping
packages/mobile/app/(tabs)/activities.tsx, packages/mobile/app/(tabs)/activities.test.tsx
useRefresh invalidates calendar.weekList, calendar.activityOverview, activity.list, and sync.dataHealth; test mocks invalidateDataHealth.
Food refresh scoping
packages/mobile/app/(tabs)/food.tsx, packages/mobile/app/(tabs)/food.test.tsx
trpcUtils invalidates food.byDate and settings.get (calorieGoal) on refresh; tests verify scoped invalidation via captured useRefresh options.
Provider detail refresh scoping
packages/mobile/app/providers/[id].tsx, packages/mobile/app/providers/[id].test.tsx
Invalidates provider records, detail logs, and sync queries (providers, providerStats, dataHealth); tests add invalidators and a scoped assertion test.
Provider list refresh scoping
packages/mobile/app/providers/index.tsx
Invalidates providers, providerStats, logs, dataHealth, activeSyncs sync queries on refresh instead of default behavior.

Non-blocking loading via shouldShowBlockingLoading

Layer / File(s) Summary
Today screen cached-data loading
packages/mobile/app/(tabs)/index.tsx, packages/mobile/app/(tabs)/index.test.tsx
Dashboard query adds placeholderData; isLoading computed via shouldShowBlockingLoading; isError only set when data is null; tests add isFetching mock and cached-content-during-refresh test.
Strain screen cached-data loading
packages/mobile/app/(tabs)/strain.tsx, packages/mobile/app/(tabs)/strain.test.tsx
isLoading computed via shouldShowBlockingLoading using trainingData, isLoading, isFetching; tests add isFetching mock and cached-content-during-refresh test.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Assessment against linked issues

Objective Addressed Explanation
Pull-to-refresh/auto-sync use targeted invalidation instead of invalidating every tRPC query (#1429)
High-traffic iOS screens do not blank content during background refetches (#1429)
sync.dataHealth cached briefly without changing response shape/hard-failure behavior (#1429) This PR wires client-side invalidation of sync.dataHealth, but no server-side caching change for dataHealth is visible in this diff.
Mobile query cache persistence shows last-known data after cold app restart (#1429) Not evidenced in this diff; only placeholderData for the dashboard query and blocking-loading logic are shown.
Failing tests written before implementation for non-blocking loading states (#1429) Cannot verify test-first ordering from the diff alone.

Possibly related PRs

  • Asherlc/dofek#1103: Both PRs keep food.byDate data from staleness via explicit invalidation, this PR via pull-to-refresh, the other via server-side mutation invalidation.
  • Asherlc/dofek#1123: Both touch ActivitiesScreen pull-to-refresh wiring around calendar.weekList invalidation.
  • Asherlc/dofek#1124: This PR extends the useRefresh-scoped invalidate pattern introduced there to more screens.

Suggested labels: area/mobile, type/bug

Suggested reviewers: cubic-dev-ai

🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title is imperative and concise, but it lacks the required area prefix for a mobile-focused change. Prefix the title with the relevant area, e.g. "[mobile] Fix slow iOS loading across mobile pages".
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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.

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Storybook previews for c7a131be are ready:

This comment updates automatically on each PR push.

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Mobile Preview

Scan to open on device:

QR code for dofek://preview/pr-1471

Channel pr-1471
Deep Link dofek://preview/pr-1471
Commit c7a131b

To test on device:

  1. Build and install the preview client: PREVIEW_CHANNEL=pr-1471 pnpm expo prebuild --clean -p ios
  2. Or tap deep link on an existing preview build: dofek://preview/pr-1471

Each PR gets its own channel. Build a preview client with PREVIEW_CHANNEL=pr-{N} to test.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 10 files

Confidence score: 3/5

  • In packages/mobile/app/providers/[id].tsx, pull-to-refresh currently misses trpcUtils.sync.providers.invalidate(), so provider metadata (name/status/last sync) can stay stale after refresh and users may see outdated connection state — add that invalidation call in useProviderDetailActions before merging.
  • In packages/mobile/app/(tabs)/food.test.tsx, the invalidation mocks are configured but never asserted, so regressions in cache invalidation behavior could slip through unnoticed — add assertions for invalidateFoodByDateMock and invalidatesettingsGetMock (including expected args) to de-risk future changes.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/mobile/app/(tabs)/food.test.tsx
Comment thread packages/mobile/app/providers/[id].tsx
@Asherlc

Asherlc commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

Addressed Cubic review #1471 (review).

Fixed.

  • Added assertions for FoodScreen scoped refresh invalidation arguments.
  • Added Provider Detail provider metadata invalidation and test coverage for the full scoped refresh list.
  • Commit: 23b15c5af

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

0 issues found across 3 files (changes from recent commits).

Auto-approved: Improves mobile performance with non-blocking cached loads and scoped refresh invalidation; includes tests.

Re-trigger cubic

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
packages/mobile/app/(tabs)/strain.tsx (1)

319-320: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse the computed isLoading instead of raw trainingQuery.isLoading.

The "Recent Activities" section still branches on trainingQuery.isLoading directly, duplicating the concept the new shouldShowBlockingLoading-derived isLoading was introduced to centralize. Practically harmless today (react-query's isLoading is only true when there's no data), but it's an inconsistency waiting to bite if the query's caching behavior changes.

♻️ Proposed fix
-            {trainingQuery.isLoading ? (
+            {isLoading ? (
               <ActivityIndicator color={colors.accent} style={styles.activitiesLoader} />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mobile/app/`(tabs)/strain.tsx around lines 319 - 320, The Recent
Activities loading branch still uses trainingQuery.isLoading directly instead of
the centralized isLoading state derived from shouldShowBlockingLoading. Update
the strain.tsx render path to use the computed isLoading consistently wherever
the loading UI is gated, so the ActivityIndicator and related logic all rely on
the same source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/mobile/app/`(tabs)/index.tsx:
- Around line 77-82: The refetch failure state is being hidden once
dashboardData exists because isError only checks for dashboardData == null.
Update the dashboard screen logic in index.tsx to distinguish initial-load
errors from stale-data refetch errors using dashboardQuery.isError with
dashboardData != null, and render a lightweight non-blocking inline error
indicator near the top of the ScrollView for that stale-data case. Keep the
existing blocking loading/error behavior for the initial load, and reuse
QueryStatePanel or a compact Text/banner-style state tied to dashboardQuery and
dashboardData.

In `@packages/mobile/app/providers/index.tsx`:
- Around line 485-494: The providers screen now has targeted invalidate wiring
in useRefresh, but there is no matching test coverage like the sibling screens.
Update providers/index.test.tsx to mirror the [id].test.tsx pattern by mocking
useRefresh and asserting that the refresh callback triggers invalidation of
sync.providers, sync.providerStats, sync.logs, sync.dataHealth, and
sync.activeSyncs from providers/index.tsx.

---

Outside diff comments:
In `@packages/mobile/app/`(tabs)/strain.tsx:
- Around line 319-320: The Recent Activities loading branch still uses
trainingQuery.isLoading directly instead of the centralized isLoading state
derived from shouldShowBlockingLoading. Update the strain.tsx render path to use
the computed isLoading consistently wherever the loading UI is gated, so the
ActivityIndicator and related logic all rely on the same source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b678cc6b-96a9-4959-803d-2ba0b49b1d49

📥 Commits

Reviewing files that changed from the base of the PR and between b16cbb0 and 23b15c5.

📒 Files selected for processing (11)
  • packages/mobile/app/(tabs)/activities.test.tsx
  • packages/mobile/app/(tabs)/activities.tsx
  • packages/mobile/app/(tabs)/food.test.tsx
  • packages/mobile/app/(tabs)/food.tsx
  • packages/mobile/app/(tabs)/index.test.tsx
  • packages/mobile/app/(tabs)/index.tsx
  • packages/mobile/app/(tabs)/strain.test.tsx
  • packages/mobile/app/(tabs)/strain.tsx
  • packages/mobile/app/providers/[id].test.tsx
  • packages/mobile/app/providers/[id].tsx
  • packages/mobile/app/providers/index.tsx
👮 Files not reviewed due to content moderation or server errors (1)
  • packages/mobile/app/(tabs)/strain.test.tsx

Comment thread packages/mobile/app/(tabs)/index.tsx
Comment thread packages/mobile/app/providers/index.tsx
@Asherlc

Asherlc commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

Addressed CodeRabbit review #1471 (review).

Fixed.

  • Today now shows a non-blocking dashboard refresh error while preserving cached content.
  • Providers index scoped refresh invalidation is covered by tests.
  • Strain Recent Activities now uses the centralized loading policy flag.
  • Commit: 8a6d759

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

0 issues found across 4 files (changes from recent commits).

Auto-approved: Optimizes mobile loading by keeping cached data visible during refresh and scoping pull-to-refresh invalidation to relevant queries.

Re-trigger cubic

Asherlc added 2 commits July 3, 2026 14:06
# Conflicts:
#	packages/mobile/app/(tabs)/food.test.tsx
#	packages/mobile/app/(tabs)/index.test.tsx
#	packages/mobile/app/(tabs)/index.tsx
#	packages/mobile/app/(tabs)/strain.test.tsx
#	packages/mobile/app/(tabs)/strain.tsx

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

0 issues found across 1 file (changes from recent commits).

Auto-approved: Improves iOS loading UX by keeping cached data visible during refreshes and scoping pull-to-refresh invalidation across mobile screens. Low risk, well-tested.

Re-trigger cubic

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.

Fix slow iOS loading across mobile pages

2 participants