Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ import { getMockEvents, getMockNetworks, getMockStats, getMockValidator, getMock
const BASE_URL = import.meta.env.VITE_API_URL || '';
const USE_MOCK = import.meta.env.VITE_USE_MOCK === 'true';

/**
* Preview-bypass for gated networks (api side: migration 052).
* Returns 'all' iff the current URL has ?preview=all, else null.
*
* Live-reads window.location each call so SPA navigation to/from the
* preview URL flips the behaviour immediately. Not cached.
*
* SSR-safe fallback (typeof window check) for future build-time
* prerendering.
*/
function previewParam(): string | null {
if (typeof window === 'undefined') return null;
const p = new URLSearchParams(window.location.search).get('preview');
return p === 'all' ? 'all' : null;
}
Comment on lines +39 to +43
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The previewParam helper is a good addition for handling gated content, but there are two significant issues with the current implementation:

  1. Incomplete Coverage: This parameter is only being passed in fetchEvents, fetchNetworks, and fetchStats. However, many other functions in this file (such as fetchValidator, fetchLeaderboard, fetchChainData, fetchDelegations, and fetchHealthCheck) likely also need to support this parameter to ensure that gated networks are visible and functional across all views (e.g., when viewing a specific validator's profile on a gated network).
  2. SPA Navigation & React Hooks: The PR description states that visibility flips "immediately" during SPA navigation. While the API client reads the URL live, the corresponding hooks (like useNetworks and useStats in src/hooks/) do not include the URL search parameters in their dependency arrays. Consequently, navigating to or from a ?preview=all URL within the SPA will not trigger a re-fetch, and the UI will not update until a manual refresh or a different state change occurs.

Consider applying this parameter to all relevant API calls and updating the hooks to react to URL search parameter changes.


export async function fetchEvents(params?: {
network?: string;
search?: string;
Expand All @@ -39,6 +55,8 @@ export async function fetchEvents(params?: {
if (params?.search) qs.set('search', params.search);
if (params?.cursor) qs.set('cursor', params.cursor);
if (params?.limit) qs.set('limit', String(params.limit));
const pv = previewParam();
if (pv) qs.set('preview', pv);
const query = qs.toString();
const res = await fetch(`${BASE_URL}/v1/events${query ? `?${query}` : ''}`);
if (!res.ok) throw new Error(`API error: ${res.status}`);
Expand All @@ -48,15 +66,19 @@ export async function fetchEvents(params?: {
export async function fetchNetworks(): Promise<DataResponse<NetworkInfo[]>> {
if (USE_MOCK) return getMockNetworks();

const res = await fetch(`${BASE_URL}/v1/networks`);
const pv = previewParam();
const suffix = pv ? `?preview=${pv}` : '';
const res = await fetch(`${BASE_URL}/v1/networks${suffix}`);
Comment on lines +69 to +71
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

For better maintainability and consistency with the approach used in fetchEvents, consider using URLSearchParams to construct the query string instead of manual string concatenation.

Suggested change
const pv = previewParam();
const suffix = pv ? `?preview=${pv}` : '';
const res = await fetch(`${BASE_URL}/v1/networks${suffix}`);
const qs = new URLSearchParams();
const pv = previewParam();
if (pv) qs.set('preview', pv);
const query = qs.toString();
const res = await fetch(`${BASE_URL}/v1/networks${query ? `?${query}` : ''}`);

if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json() as Promise<DataResponse<NetworkInfo[]>>;
}

export async function fetchStats(): Promise<DataResponse<StatsResponse>> {
if (USE_MOCK) return getMockStats();

const res = await fetch(`${BASE_URL}/v1/stats`);
const pv = previewParam();
const suffix = pv ? `?preview=${pv}` : '';
const res = await fetch(`${BASE_URL}/v1/stats${suffix}`);
Comment on lines +79 to +81
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

For better maintainability and consistency with the approach used in fetchEvents, consider using URLSearchParams to construct the query string instead of manual string concatenation.

Suggested change
const pv = previewParam();
const suffix = pv ? `?preview=${pv}` : '';
const res = await fetch(`${BASE_URL}/v1/stats${suffix}`);
const qs = new URLSearchParams();
const pv = previewParam();
if (pv) qs.set('preview', pv);
const query = qs.toString();
const res = await fetch(`${BASE_URL}/v1/stats${query ? `?${query}` : ''}`);

if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json() as Promise<DataResponse<StatsResponse>>;
}
Expand Down
Loading