diff --git a/apps/browser-extension/src/entrypoints/popup/pages/Reinitialize.tsx b/apps/browser-extension/src/entrypoints/popup/pages/Reinitialize.tsx index 30f558403..8970d7704 100644 --- a/apps/browser-extension/src/entrypoints/popup/pages/Reinitialize.tsx +++ b/apps/browser-extension/src/entrypoints/popup/pages/Reinitialize.tsx @@ -33,7 +33,7 @@ const Reinitialize: React.FC = () => { // Auth and DB state const { isInitialized: authInitialized, isLoggedIn } = useApp(); - const { dbInitialized, dbAvailable } = useDb(); + const { dbInitialized, dbAvailable, refreshSyncState } = useDb(); // Derived state const isFullyInitialized = authInitialized && dbInitialized; @@ -127,8 +127,18 @@ const Reinitialize: React.FC = () => { * 1. Download and merge (if needed) * 2. Call dbContext.loadDatabase() which updates sqliteClient * 3. ItemsList reacts to sqliteClient changes and auto-refreshes + * + * Note: onSuccess triggers refreshSyncState to ensure any UI components + * watching sync state will re-render with the updated vault data. */ syncVault({ + /** + * Handle successful sync - refresh sync state to trigger UI updates. + * @param _hasNewVault Whether a new vault was downloaded + */ + onSuccess: async (_hasNewVault) => { + await refreshSyncState(); + }, /** * Handle upgrade required - redirect to upgrade page. */ @@ -151,7 +161,7 @@ const Reinitialize: React.FC = () => { }; handleInitialization(); - }, [isFullyInitialized, requiresAuth, isLoggedIn, dbAvailable, navigate, setIsInitialLoading, syncVault, restoreLastPage]); + }, [isFullyInitialized, requiresAuth, isLoggedIn, dbAvailable, navigate, setIsInitialLoading, syncVault, restoreLastPage, refreshSyncState]); // This component doesn't render anything visible - it just handles initialization return null; diff --git a/apps/mobile-app/app/(tabs)/items/index.tsx b/apps/mobile-app/app/(tabs)/items/index.tsx index 172cdb451..4a4faa39b 100644 --- a/apps/mobile-app/app/(tabs)/items/index.tsx +++ b/apps/mobile-app/app/(tabs)/items/index.tsx @@ -360,6 +360,25 @@ export default function ItemsScreen(): React.ReactNode { loadItems(); }, [isAuthenticated, isDatabaseAvailable, loadItems, setIsLoadingItems]); + /** + * Track previous syncing state to detect when sync completes. + */ + const wasSyncingRef = useRef(dbContext.isSyncing); + + /** + * Reload items when background sync completes (isSyncing goes from true to false). + * This ensures newly synced data is displayed without requiring manual pull-to-refresh. + */ + useEffect(() => { + const wasSyncing = wasSyncingRef.current; + wasSyncingRef.current = dbContext.isSyncing; + + // Only reload when sync just completed (was syncing, now not syncing) + if (wasSyncing && !dbContext.isSyncing && isAuthenticated && isDatabaseAvailable) { + loadItems(); + } + }, [dbContext.isSyncing, isAuthenticated, isDatabaseAvailable, loadItems]); + // Set header for Android useEffect(() => { navigation.setOptions({