Skip to content

Add Auto-Refresh on Page Focus and Manual Refresh Button#204

Open
codybrouwers wants to merge 5 commits intobenvinegar:mainfrom
codybrouwers:add-refreshing-on-page-focus
Open

Add Auto-Refresh on Page Focus and Manual Refresh Button#204
codybrouwers wants to merge 5 commits intobenvinegar:mainfrom
codybrouwers:add-refreshing-on-page-focus

Conversation

@codybrouwers
Copy link

@codybrouwers codybrouwers commented Jul 23, 2025

Overview

This PR adds automatic data refreshing when users return to the dashboard tab/window, along with a manual refresh button for on-demand updates. To implement this cleanly, the data fetching architecture was refactored to move useFetcher into the PaginatedTableCard component with improved type safety.

Features Added

🔄 Auto-Refresh on Page Focus

  • Dashboard automatically refreshes data when the page regains focus (tab switching, window focus, etc.)
  • Uses both visibilitychange and focus events for comprehensive coverage
  • Includes 1-second debouncing to prevent excessive API calls during rapid focus changes

🔃 Manual Refresh Button

  • Added a prominent refresh button to the dashboard header
  • Shows loading spinner animation during refresh
  • Provides immediate user control over data updates

Technical Changes

Architecture Refactoring

  • Moved data fetching logic: useFetcher now lives inside PaginatedTableCard instead of being passed as a prop
  • Type safety improvements: Added generic type parameter to PaginatedTableCard that ensures type-safe data fetching
  • Simplified component interface: Removed dataFetcher prop, making the component more self-contained

Component Updates

  • PaginatedTableCard: Refactor to manage its own data fetching with improved URL parameter handling and change detection
  • TableCard: Enhanced type handling for CountByProperty to support both string and number values
  • Dashboard: Added refresh functionality with debouncing and proper event cleanup
  • All resource components: Updated to use the new type-safe PaginatedTableCard interface

Type System Improvements

  • Exported CountByProperty type for better type sharing
  • Added proper typing for loader functions with context parameters
  • Improved type safety across data fetching boundary

Implementation Details

  • Debouncing: 1-second cooldown prevents multiple refresh calls during rapid focus events
  • Browser compatibility: Uses modern Visibility API, gracefully degrades for older browsers
  • Performance: Only triggers API calls when parameters actually change
  • UX: Loading states properly reflected in UI with opacity changes and spinner animations

…eric support

- Changed import statements for `AppLoadContext` and `PlatformProxy` to use type-only imports.
- Updated `Cloudflare` type to be exported.
- Enhanced `PaginatedTableCard` to accept generic types for better type safety.
- Modified `TableCard` to handle `CountByProperty` more robustly.
- Adjusted various route components to utilize the updated `PaginatedTableCard` and loader types, ensuring proper type definitions for `analyticsEngine` and `cloudflare` in loaders.
@codybrouwers codybrouwers changed the title Add refreshing on page focus Add Auto-Refresh on Page Focus and Manual Refresh Button Jul 23, 2025
@benvinegar benvinegar requested a review from Copilot July 27, 2025 07:27
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements auto-refresh functionality for the dashboard when users return to the page, along with a manual refresh button. The changes include refactoring the data fetching architecture by moving useFetcher into the PaginatedTableCard component and improving type safety throughout.

  • Auto-refresh on page focus with debouncing to prevent excessive API calls
  • Manual refresh button with loading state indication
  • Refactored data fetching to be self-contained within PaginatedTableCard with improved type safety

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/server/app/routes/dashboard.tsx Added auto-refresh on focus/visibility change and manual refresh button with proper event handling
packages/server/app/components/PaginatedTableCard.tsx Refactored to manage its own data fetching with generic typing and parameter change detection
packages/server/app/components/TableCard.tsx Enhanced type handling for CountByProperty to support string/number values and improved type safety
packages/server/app/load-context.ts Exported Cloudflare type for better type sharing
Resource route files Updated to use new type-safe PaginatedTableCard interface, removing dataFetcher prop
Comments suppressed due to low confidence (1)

packages/server/app/components/PaginatedTableCard.tsx:19

  • [nitpick] The generic type parameter T is not descriptive. Consider renaming it to TLoader or LoaderFunction to better indicate its purpose as a loader function type.
const PaginatedTableCard = <T extends (...args: any[]) => Promise<{ countsByProperty: CountByProperty }>>({

export async function loader({ context, request }: LoaderFunctionArgs<{
analyticsEngine: AnalyticsEngineAPI;
}>) {
const { analyticsEngine } = context || {};
Copy link

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

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

Using optional chaining on context could lead to undefined behavior. The destructuring assignment will fail if context is null/undefined, making the null check ineffective. Consider checking context first: if (!context) throw new Error("Context is not defined"); const { analyticsEngine } = context;

Suggested change
const { analyticsEngine } = context || {};
if (!context) throw new Error("Context is not defined");
const { analyticsEngine } = context;

Copilot uses AI. Check for mistakes.
lastParamsRef.current = fullUrl;
fetcher.load(fullUrl);
}
}, [fetcher.load, loaderUrl, siteId, interval, filters, timezone, page]);
Copy link

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

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

Including fetcher.load in the dependency array can cause infinite re-renders since fetcher.load is not a stable reference and changes on each render. Remove fetcher.load from the dependency array as it's not needed for the callback's functionality.

Suggested change
}, [fetcher.load, loaderUrl, siteId, interval, filters, timezone, page]);
}, [loaderUrl, siteId, interval, filters, timezone, page]);

Copilot uses AI. Check for mistakes.
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.

2 participants