Skip to content

Changes :#41

Merged
aryansoni-dev merged 3 commits into
mainfrom
dev
Jun 23, 2026
Merged

Changes :#41
aryansoni-dev merged 3 commits into
mainfrom
dev

Conversation

@aryansoni-dev

@aryansoni-dev aryansoni-dev commented Jun 23, 2026

Copy link
Copy Markdown
Owner

[+] Implemented code-rabbit's suggested bug fixes and improvements.
[+] Improved the app's error handling and state management for better user experience.

Summary by CodeRabbit

  • New Features

    • Added reusable screen state components (empty/loading/error), filtered empty states, inline updating pill, and retry-capable stale-data notice.
    • Introduced delayed “Preparing…” hydration UI across multiple screens.
    • Enhanced insights/report empty states and error banners with retry actions.
  • Bug Fixes

    • Improved hydration-aware loading/error rendering and gating (including AI report refresh and chat/achievements state).
    • Refined retry behavior to clear errors before retrying.
  • UI/UX

    • Unified theme-based styling for error/offline/sync indicators and updated various empty-state and button text.
    • Disabled reminder time interactions until hydration completes; improved export/journal labeling consistency.

  [+] Implemented code-rabbit's suggested bug fixes and improvements.
  [+] Improved the app's error handling and state management for better user experience.
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

A comprehensive screen state audit introduces six reusable UI state components, a delayed-visibility hook, per-store hydration tracking, persisted-data validation, semantic color theme tokens, development fault injection, and applies these across every major screen to standardize loading, empty, error, and retry behaviors.

Changes

Screen State Audit & Resilience Hardening

Layer / File(s) Summary
Type contracts and semantic theme constants
types/uiState.ts, types/appError.ts, lib/utils/typeGuards.ts, constants/theme.ts, global.css
Introduces DataFreshness, LoadableStatus, EmptyStateReason, RetryState UI state types; refactors AppErrorCode to derive from appErrorCodes const tuple; exports shared isRecord guard; adds colors, CONNECTION_STATE_COLORS, SYNC_STATUS_COLORS theme maps and CSS custom properties.
Reusable screen-state components
components/states/ScreenLoadingState.tsx, components/states/ScreenEmptyState.tsx, components/states/ScreenErrorState.tsx, components/states/FilteredEmptyState.tsx, components/states/InlineRefreshState.tsx, components/states/StaleDataNotice.tsx, components/insights/report/ReportScreenStates.tsx
Introduces six new UI components for loading, empty, error, filtered-empty, inline-refresh, and stale-data states; extends ErrorBanner with optional onRetry callback and retrying flag for retry flow control.
Delayed visibility and history view-state helpers
hooks/useDelayedVisibility.ts, lib/ui/deriveHistoryViewState.ts
New useDelayedVisibility hook defers UI appearance by configurable timeout to reduce hydration flicker; deriveHistoryViewState helper maps hydration/filter/entry presence into LoadableStatus and EmptyStateReason for consistent screen rendering.
Consolidate shared isRecord guard
lib/utils/typeGuards.ts, lib/errors/normalizeAppError.ts, lib/account/accountDeletionService.ts, store/useSyncStore.ts, plus two additional modules
Replaces five file-local isRecord definitions with shared utility import, reducing duplication and centralizing type-guard logic.
Fault injection infrastructure and AI service wiring
types/faultInjection.ts, lib/dev/faultInjection.ts, lib/ai/entryReflectionService.ts, lib/ai/remoteJournalAssistant.ts, lib/insights/aiInsightReportService.ts
Adds FaultInjectionKey type and development-only isFaultEnabled/throwIfFaultEnabled helpers; wires fault checks into AI services to force timeout, empty-response, and invalid-response failures for testing.
Persisted data validation and normalization
lib/validation/persistedDataValidators.ts
Introduces normalizePersistedJournalEntries and normalizePersistedChatMessages with strict runtime shape validation, deduplication by scoped userId:id key, and dev-only quarantine diagnostics; exports timestamp, string, and reminder-time validation helpers.
Fault-aware persistence storage and Zustand wiring
lib/storage/createPersistStorage.ts, store/journal-store.ts, store/notification-preferences-store.ts, store/onboarding-store.ts, store/useAchievementStore.ts, store/useSyncStore.ts
Introduces createPersistStorage factory that injects fault checks on AsyncStorage read/write; updates all persisted stores to use new storage, sanitize rehydrated state via merge, normalize via migration, and use partialize for selective persistence.
Store hydration tracking
store/useAIInsightReportStore.ts, store/useChatStore.ts, store/useEntryReflectionStore.ts
Adds hasHydrated flag and setHasHydrated action to all three stores; configures onRehydrateStorage to set flag to true after rehydration; uses partialize to exclude flag from persistence; tightens persisted reflection field validation.
AI cache-hydration gating and error normalization
hooks/useAIInsightReport.ts, hooks/useEntryReflection.ts
Both hooks early-return when cacheHasHydrated is false; use reportRef/requestGenerationRef to prevent stale async outcomes; widen isLoading to include unhydrated cache state; normalize error messages via normalizeAppError with operation context.
Session-aware sync guards and route validation
lib/sync/requestSync.ts, lib/validation/activeUser.ts, lib/navigation/routeValidators.ts
Adds isActiveUser guards that return session_expired (retryable: false) if user changes during sync stages; switches failed-entry lookup to Set membership; marks missing Supabase config as non-retryable; introduces getSingleRouteParam and getSafeRouteId for safe route parameter extraction.
Account deletion batching and auto-sync refinements
supabase/functions/delete-account/index.ts, components/sync/auto-sync-manager.tsx, hooks/useAutoSync.ts
Batches storage removal operations by 1000 items with per-batch error handling; moves auto-sync retry counter increment inside setTimeout callback; removes unused startOfLocalDay helper.
Journal history and calendar state rendering
components/journal-history/journal-history-screen.tsx, components/journal-history/journal-calendar-view.tsx
Replaces manual hasHydrated checks with deriveHistoryViewState-driven conditionals and FilteredEmptyState with clear-filters action in history. Calendar uses useDelayedVisibility for hydration delay and conditions empty-state on overall/month/day entry counts.
Journal editor and AI reflection card states
components/journal-editor/journal-editor-screen.tsx, components/journal-editor/entry-ai-reflection-card.tsx
Replaces static hydration text with delayed-visibility ScreenLoadingState; updates save-failure and missing-entry copy; adjusts save-button label logic. Reflection card adds loading-guarded early return and improves error prefixes for generate/update paths.
AI chat, home, and achievements screens
components/ai-chat/ai-chat-screen.tsx, components/home/home-screen.tsx, components/achievements/AchievementsScreen.tsx
Chat gates message visibility/send on chatHasHydrated; adds hydration banner and theme-driven connection colors; resets thinking on user change. Home uses delayed hydration empty-state and optional CTA. Achievements adds delayed loading and filter-driven empty states.
Insights and report screens
components/insights/insights-screen.tsx, app/insights/report/[periodType].tsx
Insights adds no-entry empty-state with navigation to journal creation; refines loading logic. Report screen wires ErrorBanner retry to reportState.refresh() and conditions updating/loading banners on report presence.
Notification settings and profile screens
components/profile/notification-settings-screen.tsx, components/profile/profile-screen.tsx
Notification screen shows hydration-dependent status and disables reminder rows pre-hydration; row gains disabled prop. Profile fixes sign-out token clearing order (after successful sign-out), updates export-journal copy, and shows loading state on export menu.
Hardcoded color to theme token migration
components/sync/SyncStatusIndicator.tsx, components/sync/SyncStatusRow.tsx, components/errors/FeatureErrorBoundary.tsx, components/errors/InlineErrorMessage.tsx, components/errors/RootErrorFallback.tsx, components/connectivity/OfflineNotice.tsx, components/legal/legal-document-screen.tsx
Replaces hardcoded hex colors with semantic Tailwind tokens and theme color maps; refactors legal screen layout from inline styles to className-based sizing with section fallback handling.
Route parameter safety adoption
app/(tabs)/journal-editor/index.tsx, app/journal/[id].tsx
Updates screens to normalize route parameters via getSingleRouteParam and getSafeRouteId utilities for safe extraction and validation.
Screen state audit and crash/edge-case documentation
docs/screen-state-audit.md, docs/crash-edge-case-test-plan.md
Adds screen-state audit documenting per-screen hydration signals, expected UI behavior, shared gating signals, and retry operations. Adds crash-test plan with fault injection usage, manual test matrix (CE-001 to CE-026), and regression checklist.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • aryansoni-dev/dear-diary#30: Both PRs modify components/ai-chat/ai-chat-screen.tsx around hydration gating, message visibility, send behavior, and request/thinking state management.
  • aryansoni-dev/dear-diary#38: Both PRs update hooks/useAIInsightReport.ts—this PR adds cache-hydration gating and error normalization while the related PR modifies report staleness logic.
  • aryansoni-dev/dear-diary#40: Both PRs update error-handling components (FeatureErrorBoundary, InlineErrorMessage, RootErrorFallback) and AI Chat connectivity behavior with overlapping code-level changes.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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.
Title check ❓ Inconclusive The title 'Changes :' is vague and generic, using a non-descriptive term that does not convey meaningful information about the extensive changeset. Replace with a specific title that captures the main theme, such as 'Refactor error handling and hydration states across screens' or 'Implement unified screen state management and error recovery flows'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: dependency version conflict. Check your lock file or package.json.


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

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

Caution

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

⚠️ Outside diff range comments (1)
components/journal-editor/journal-editor-screen.tsx (1)

835-840: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

!wasSaved early return hides real sync state for existing entries.

This change makes the label show "Save" even when an existing entry is already synced, so users lose accurate state feedback ("Synced", "Syncing", "Saved locally").

Suggested fix
-  if (!wasSaved) {
+  if (!wasSaved && entrySyncStatus !== "synced") {
     return "Save";
   }
🤖 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 `@components/journal-editor/journal-editor-screen.tsx` around lines 835 - 840,
The early return in the button label logic when !wasSaved is true prevents
checking the real sync state of existing entries. Reorder the conditional checks
so that the entrySyncStatus conditions (checking for "synced", "syncing", etc.)
are evaluated before or independently of the !wasSaved check. This ensures that
entries with actual sync status ("Synced", "Syncing", "Saved locally") display
the correct state feedback instead of defaulting to "Save" label, allowing users
to see accurate sync information for existing entries.
🤖 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 `@components/insights/insights-screen.tsx`:
- Around line 518-520: The loading state logic in the isLoading variable does
not account for which report is actually selected for display. Since the code
uses monthlyReport ?? weeklyReport to determine the displayed report, the
loading state should only reflect the loading status of the selected report, not
both reports independently. Modify the isLoading logic to check only the loading
state of the report that will actually be displayed, so that loading is not
shown when the selected report data is already available even if the unselected
report is still loading.

In `@components/journal-editor/journal-editor-screen.tsx`:
- Around line 303-306: The message property in the save-failure dialog contains
a ternary operator that checks appError.code === "local_save_failed" but both
branches return the identical string, making the condition pointless. Remove the
ternary operator and its condition entirely, replacing it with just the single
string message that should be displayed in both cases.

In `@components/journal-history/journal-calendar-view.tsx`:
- Around line 241-255: The month-level empty state (CalendarEmptyState
component) and the per-day empty state both render when the month has no
entries, creating redundant stacked empty cards. Locate the per-day empty state
block around line 270-273 that renders "Nothing written here yet." and add a
condition to suppress it when calendarMonth.totalEntries === 0, so the
month-level empty state is the only one displayed when there are no entries for
the entire month.

In `@constants/theme.ts`:
- Around line 32-67: Extract the hardcoded hex color values from the
SYNC_STATUS_COLORS object to semantic color constants in the colors object for
consistency. Identify all hardcoded colors in SYNC_STATUS_COLORS (such as the
background and text colors for failed, saved_locally, syncing, and other
statuses) and create corresponding semantic palette entries in the colors object
with meaningful names. Then replace the hardcoded hex values in
SYNC_STATUS_COLORS with references to these new semantic color constants,
similar to how colors.textMuted, colors.offlineSurface, and colors.offlineIcon
are already being used for some statuses.
- Around line 19-30: The CONNECTION_STATE_COLORS object contains hardcoded hex
color values for the online state (background, dot, and text properties) that
are not referenced from the colors palette, breaking consistency with the
offline state which correctly uses colors.offlineSurface and colors.offlineIcon.
Extract the three hardcoded online colors (`#CFF8E6`, `#10B981`, `#047857`) by adding
them to the colors object with semantic names (such as onlineSurface,
onlineIcon, onlineText or similar naming convention), then update the
CONNECTION_STATE_COLORS online object to reference these new colors properties
instead of the hardcoded hex values to match the pattern used for the offline
state.

In `@docs/screen-state-audit.md`:
- Around line 9-26: The Journal History row in the audit table contains an
incorrect copy string in the "First Empty" column that reads "Your journal
begins here" but should match the actual implementation showing "Write your
first entry and it will appear here." Update this cell to reflect the correct
string. Additionally, verify whether the Error, Offline, Refreshing, and Retry
columns for both HomeScreen and JournalHistoryScreen are truly implemented at
the component or parent level (such as error boundaries or sync providers), or
if these states are not yet implemented and should be marked as N/A or pending
in the table; update the table entries accordingly based on your verification
findings.

---

Outside diff comments:
In `@components/journal-editor/journal-editor-screen.tsx`:
- Around line 835-840: The early return in the button label logic when !wasSaved
is true prevents checking the real sync state of existing entries. Reorder the
conditional checks so that the entrySyncStatus conditions (checking for
"synced", "syncing", etc.) are evaluated before or independently of the
!wasSaved check. This ensures that entries with actual sync status ("Synced",
"Syncing", "Saved locally") display the correct state feedback instead of
defaulting to "Save" label, allowing users to see accurate sync information for
existing entries.
🪄 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 Plus

Run ID: 30557bfc-ccd3-4ff0-8c77-3ca2b3d1f95a

📥 Commits

Reviewing files that changed from the base of the PR and between aae9a4d and 3429908.

📒 Files selected for processing (45)
  • app/insights/report/[periodType].tsx
  • components/achievements/AchievementsScreen.tsx
  • components/ai-chat/ai-chat-screen.tsx
  • components/connectivity/OfflineNotice.tsx
  • components/errors/FeatureErrorBoundary.tsx
  • components/errors/InlineErrorMessage.tsx
  • components/errors/RootErrorFallback.tsx
  • components/home/home-screen.tsx
  • components/insights/insights-screen.tsx
  • components/insights/report/ReportScreenStates.tsx
  • components/journal-editor/entry-ai-reflection-card.tsx
  • components/journal-editor/journal-editor-screen.tsx
  • components/journal-history/journal-calendar-view.tsx
  • components/journal-history/journal-history-screen.tsx
  • components/legal/legal-document-screen.tsx
  • components/profile/notification-settings-screen.tsx
  • components/profile/profile-screen.tsx
  • components/states/FilteredEmptyState.tsx
  • components/states/InlineRefreshState.tsx
  • components/states/ScreenEmptyState.tsx
  • components/states/ScreenErrorState.tsx
  • components/states/ScreenLoadingState.tsx
  • components/states/StaleDataNotice.tsx
  • components/sync/SyncStatusIndicator.tsx
  • components/sync/SyncStatusRow.tsx
  • components/sync/auto-sync-manager.tsx
  • constants/theme.ts
  • docs/screen-state-audit.md
  • global.css
  • hooks/useAIInsightReport.ts
  • hooks/useAutoSync.ts
  • hooks/useDelayedVisibility.ts
  • hooks/useEntryReflection.ts
  • lib/account/accountDeletionService.ts
  • lib/errors/normalizeAppError.ts
  • lib/sync/requestSync.ts
  • lib/ui/deriveHistoryViewState.ts
  • lib/utils/typeGuards.ts
  • store/useAIInsightReportStore.ts
  • store/useChatStore.ts
  • store/useEntryReflectionStore.ts
  • store/useSyncStore.ts
  • supabase/functions/delete-account/index.ts
  • types/appError.ts
  • types/uiState.ts
💤 Files with no reviewable changes (1)
  • hooks/useAutoSync.ts

Comment thread components/insights/insights-screen.tsx Outdated
Comment thread components/journal-editor/journal-editor-screen.tsx Outdated
Comment thread components/journal-history/journal-calendar-view.tsx
Comment thread constants/theme.ts
Comment thread constants/theme.ts
Comment thread docs/screen-state-audit.md
  [+] Completed the Crash, Recovery, and Edge-Case Hardening Sprint for DearDiary.
  [+] Implemented code-rabbit's suggested bug fixes & improvements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (4)
store/journal-store.ts (1)

308-320: 🗄️ Data Integrity & Integration | 🟠 Major

Persisted-data sanitization runs only on version migration, not on same-version rehydration.

normalizePersistedJournalEntries is wired into migrate only. Zustand's persist invokes migrate exclusively when the stored version differs from version (3). For a returning user already at version 3, a normal cold launch sets the persisted allEntries directly, and onRehydrateStorage only calls setActiveUserId and setHasHydrated without sanitizing.

This means duplicate scoped IDs and malformed/invalid-timestamp records are not quarantined once the store reaches the current version. Add normalization to onRehydrateStorage or introduce a merge function that sanitizes on every rehydration, ensuring corrupted data does not persist indefinitely.

🤖 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 `@store/journal-store.ts` around lines 308 - 320, The journal store's data
sanitization through normalizePersistedJournalEntries is only applied during the
migrate function, which runs only when stored versions differ from the current
version. Users already at the current version bypass migration and rehydrate
directly, causing the onRehydrateStorage callback to skip sanitization. To fix
this, add a call to normalizePersistedJournalEntries in the onRehydrateStorage
callback to ensure corrupted entries with duplicate scoped IDs and invalid
timestamps are sanitized on every rehydration, not just during version
migrations. This ensures the allEntries data is always cleaned up before being
used by the store.
store/useAchievementStore.ts (1)

173-177: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: Consider consolidating the local isRecord with the shared utility.

The local isRecord function at lines 173–177 is identical to the shared isRecord exported from lib/utils/typeGuards.ts (already used by other stores in this change cohort). Since the file already imports from lib/validation/persistedDataValidators and lib/storage/createPersistStorage, adding one more import would reduce duplication.

This is pre-existing, not introduced by this change, so it's optional.

♻️ Consolidation diff
+import { isRecord } from "`@/lib/utils/typeGuards`";
 import { createPersistStorage } from "`@/lib/storage/createPersistStorage`";
 import { isNonEmptyString } from "`@/lib/validation/persistedDataValidators`";
 
 // ... rest of file
 
-function isRecord(value: unknown): value is Record<string, unknown> {
-  return (
-    typeof value === "object" && value !== null && !Array.isArray(value)
-  );
-}
🤖 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 `@store/useAchievementStore.ts` around lines 173 - 177, Remove the local
isRecord function definition from useAchievementStore.ts and import it from the
shared utility file lib/utils/typeGuards.ts instead. Add the import statement to
the existing import group from lib modules at the top of the file. This
eliminates code duplication since the isRecord type guard is already available
and used by other stores in the codebase.
store/useAIInsightReportStore.ts (1)

78-82: 📐 Maintainability & Code Quality | 🟠 Major

Add a merge function to validate and sanitize persisted state on every rehydration for consistency with other stores.

The notification preferences, onboarding, and achievements stores all use merge functions to validate persisted data during rehydration. This store uses only migrate (which runs only on version changes), leaving corrupted reportsByUser data vulnerable when the persisted version matches the current version.

Add a merge function like the other stores to ensure reportsByUser is validated on every rehydration:

Example merge pattern from notification-preferences-store
merge: (persistedState, currentState) => ({
  ...currentState,
  ...getSanitizedNotificationPreferences(persistedState),
}),
🤖 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 `@store/useAIInsightReportStore.ts` around lines 78 - 82, Add a `merge`
function to the persist configuration in useAIInsightReportStore (alongside the
existing onRehydrateStorage, partialize, and storage options) that validates and
sanitizes the persisted reportsByUser data on every rehydration. The merge
function should accept persistedState and currentState parameters, combine the
current state with sanitized/validated reportsByUser from the persisted state
(creating a helper function similar to getSanitizedNotificationPreferences used
in other stores), and return the merged result to ensure data integrity
regardless of whether a version migration occurs.
components/journal-editor/journal-editor-screen.tsx (1)

832-846: 🎯 Functional Correctness | 🟠 Major

Fix button label to reflect unsaved local changes when editing a synced entry.

When a user edits an existing synced entry and makes local changes, the button label returns "Synced" without considering that wasSaved is false. The logic at line 833 checks entrySyncStatus === "synced" first and returns immediately, preventing the code from reaching the wasSaved check at line 845. This misleads users into thinking their edits are already saved.

Restructure the logic to prioritize unsaved local edits: check wasSaved before returning "Synced", or move the synced check after verifying that no local changes exist.

🤖 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 `@components/journal-editor/journal-editor-screen.tsx` around lines 832 - 846,
The button label logic returns "Synced" immediately when entrySyncStatus equals
"synced" without checking if wasSaved is false, which masks unsaved local edits.
Restructure the conditional checks to prioritize the wasSaved state by either
adding a wasSaved check within the entrySyncStatus === "synced" condition
(returning "Synced" only if both entrySyncStatus is synced AND wasSaved is
true), or by moving the synced check after the wasSaved check. This ensures that
when a user edits a previously synced entry, the button reflects that there are
unsaved local changes rather than showing "Synced".
🤖 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 `@components/journal-editor/journal-editor-screen.tsx`:
- Around line 303-304: The hardcoded error message in the message property
around line 303-304 in journal-editor-screen.tsx does not match the normalized
error message returned by the normalizeAppError function called with operation
"local_save_journal_entry" on line 292. Update the hardcoded message string to
end with "before leaving this screen." instead of "before leaving." to ensure
consistency with the normalized error message.

In `@lib/ai/remoteJournalAssistant.ts`:
- Around line 31-40: The fault-injection error throws in
remoteJournalAssistant.ts use generic Error class, while other services like
entryReflectionService.ts and aiInsightReportService.ts use custom error classes
for consistency. Create a RemoteJournalAssistantError custom error class at the
top of the file with a structured error code property, then update the error
throws in the fault-injection blocks (the ones in isFaultEnabled checks for
ai_empty_response and ai_invalid_response) to use this new
RemoteJournalAssistantError class instead of generic Error. Optionally apply the
same pattern to any other error throws in the file for full consistency.

In `@lib/validation/persistedDataValidators.ts`:
- Around line 187-211: The relatedEntryIds property in the return object is
assigned directly without an explicit type cast, while the role and source
properties both use `as` type casts for consistency and clarity. Add an explicit
type cast to relatedEntryIds by changing `relatedEntryIds:
value.relatedEntryIds,` to `relatedEntryIds: value.relatedEntryIds as string[] |
undefined,` to align with the established casting pattern used for role and
source properties and make the type intent explicit.

---

Outside diff comments:
In `@components/journal-editor/journal-editor-screen.tsx`:
- Around line 832-846: The button label logic returns "Synced" immediately when
entrySyncStatus equals "synced" without checking if wasSaved is false, which
masks unsaved local edits. Restructure the conditional checks to prioritize the
wasSaved state by either adding a wasSaved check within the entrySyncStatus ===
"synced" condition (returning "Synced" only if both entrySyncStatus is synced
AND wasSaved is true), or by moving the synced check after the wasSaved check.
This ensures that when a user edits a previously synced entry, the button
reflects that there are unsaved local changes rather than showing "Synced".

In `@store/journal-store.ts`:
- Around line 308-320: The journal store's data sanitization through
normalizePersistedJournalEntries is only applied during the migrate function,
which runs only when stored versions differ from the current version. Users
already at the current version bypass migration and rehydrate directly, causing
the onRehydrateStorage callback to skip sanitization. To fix this, add a call to
normalizePersistedJournalEntries in the onRehydrateStorage callback to ensure
corrupted entries with duplicate scoped IDs and invalid timestamps are sanitized
on every rehydration, not just during version migrations. This ensures the
allEntries data is always cleaned up before being used by the store.

In `@store/useAchievementStore.ts`:
- Around line 173-177: Remove the local isRecord function definition from
useAchievementStore.ts and import it from the shared utility file
lib/utils/typeGuards.ts instead. Add the import statement to the existing import
group from lib modules at the top of the file. This eliminates code duplication
since the isRecord type guard is already available and used by other stores in
the codebase.

In `@store/useAIInsightReportStore.ts`:
- Around line 78-82: Add a `merge` function to the persist configuration in
useAIInsightReportStore (alongside the existing onRehydrateStorage, partialize,
and storage options) that validates and sanitizes the persisted reportsByUser
data on every rehydration. The merge function should accept persistedState and
currentState parameters, combine the current state with sanitized/validated
reportsByUser from the persisted state (creating a helper function similar to
getSanitizedNotificationPreferences used in other stores), and return the merged
result to ensure data integrity regardless of whether a version migration
occurs.
🪄 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 Plus

Run ID: 540a4478-05a5-41c8-ac03-8a697d4d9e45

📥 Commits

Reviewing files that changed from the base of the PR and between 3429908 and e17cda9.

📒 Files selected for processing (28)
  • app/(tabs)/journal-editor/index.tsx
  • app/journal/[id].tsx
  • components/ai-chat/ai-chat-screen.tsx
  • components/insights/insights-screen.tsx
  • components/journal-editor/journal-editor-screen.tsx
  • components/journal-history/journal-calendar-view.tsx
  • constants/theme.ts
  • docs/crash-edge-case-test-plan.md
  • docs/screen-state-audit.md
  • hooks/useEntryReflection.ts
  • lib/ai/entryReflectionService.ts
  • lib/ai/remoteJournalAssistant.ts
  • lib/dev/faultInjection.ts
  • lib/insights/aiInsightReportService.ts
  • lib/navigation/routeValidators.ts
  • lib/storage/createPersistStorage.ts
  • lib/sync/requestSync.ts
  • lib/validation/activeUser.ts
  • lib/validation/persistedDataValidators.ts
  • store/journal-store.ts
  • store/notification-preferences-store.ts
  • store/onboarding-store.ts
  • store/useAIInsightReportStore.ts
  • store/useAchievementStore.ts
  • store/useChatStore.ts
  • store/useEntryReflectionStore.ts
  • store/useSyncStore.ts
  • types/faultInjection.ts

Comment thread components/journal-editor/journal-editor-screen.tsx Outdated
Comment thread lib/ai/remoteJournalAssistant.ts
Comment thread lib/validation/persistedDataValidators.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@store/journal-store.ts`:
- Around line 311-323: The onRehydrateStorage callback in Zustand 5 receives two
parameters (state and error), but the current implementation only accepts state
and returns early when state is falsy, leaving hasHydrated at false and causing
the loading screen to hang. Update the onRehydrateStorage callback to capture
both the state parameter and the error parameter. When state is falsy
(indicating a storage failure), still call useJournalStore.setState with
hasHydrated set to true to ensure the application can proceed past the loading
state. Keep the existing logic for the success path where state exists and
normalizePersistedJournalEntries is called.
🪄 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 Plus

Run ID: c60db5b9-3459-435c-8815-498fe38f3481

📥 Commits

Reviewing files that changed from the base of the PR and between e17cda9 and b322f66.

📒 Files selected for processing (6)
  • components/journal-editor/journal-editor-screen.tsx
  • lib/ai/remoteJournalAssistant.ts
  • lib/validation/persistedDataValidators.ts
  • store/journal-store.ts
  • store/useAIInsightReportStore.ts
  • store/useAchievementStore.ts

Comment thread store/journal-store.ts
@aryansoni-dev aryansoni-dev merged commit a952402 into main Jun 23, 2026
1 check passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 3, 2026
Merged
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.

1 participant