Suppress network error toasts, use mock data fallback
This commit is contained in:
@@ -41,9 +41,33 @@ export default function OverviewPage() {
|
||||
}
|
||||
|
||||
if (error) {
|
||||
// Check if it's a network error (API not available)
|
||||
const isNetworkError = (error as any)?.message?.includes('Network') ||
|
||||
(error as any)?.code === 'ERR_NETWORK';
|
||||
|
||||
return (
|
||||
<div className="page-container">
|
||||
<div className="error-state">Error loading dashboard data</div>
|
||||
<div className="error-state">
|
||||
{isNetworkError ? (
|
||||
<div>
|
||||
<h2>API Connection Error</h2>
|
||||
<p>The backend API is not available at {import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000'}</p>
|
||||
<p>Please ensure the API server is running.</p>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => window.location.reload()}
|
||||
style={{ marginTop: '1rem' }}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<h2>Error loading dashboard data</h2>
|
||||
<p>{(error as Error).message}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -160,9 +160,10 @@ class ApiClient {
|
||||
toast.error(message);
|
||||
}
|
||||
} else if (error.request) {
|
||||
// Network error
|
||||
// Network error - API not reachable
|
||||
logger.error('Network error', error, { url: error.config?.url });
|
||||
toast.error(ERROR_MESSAGES.NETWORK_ERROR);
|
||||
// Don't show toast for network errors - let components handle with mock data
|
||||
// toast.error(ERROR_MESSAGES.NETWORK_ERROR);
|
||||
} else {
|
||||
logger.error('Request setup error', error);
|
||||
toast.error(ERROR_MESSAGES.UNEXPECTED_ERROR);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// DBIS Admin API Service
|
||||
import { apiClient } from './client';
|
||||
import { mockGlobalOverview, mockParticipants } from '@/utils/mockData';
|
||||
import type {
|
||||
NetworkHealthStatus,
|
||||
SettlementThroughput,
|
||||
@@ -35,12 +36,30 @@ export interface JurisdictionSettings {
|
||||
class DBISAdminAPI {
|
||||
// Global Overview
|
||||
async getGlobalOverview(): Promise<GlobalOverviewDashboard> {
|
||||
return apiClient.get<GlobalOverviewDashboard>('/api/admin/dbis/dashboard/overview');
|
||||
try {
|
||||
return await apiClient.get<GlobalOverviewDashboard>('/api/admin/dbis/dashboard/overview');
|
||||
} catch (error: any) {
|
||||
// If API is not available, return mock data for development
|
||||
if (error?.code === 'ERR_NETWORK' || error?.message?.includes('Network')) {
|
||||
console.warn('API not available, using mock data');
|
||||
return mockGlobalOverview as GlobalOverviewDashboard;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Participants
|
||||
async getParticipants(): Promise<ParticipantInfo[]> {
|
||||
return apiClient.get<ParticipantInfo[]>('/api/admin/dbis/participants');
|
||||
try {
|
||||
return await apiClient.get<ParticipantInfo[]>('/api/admin/dbis/participants');
|
||||
} catch (error: any) {
|
||||
// If API is not available, return mock data for development
|
||||
if (error?.code === 'ERR_NETWORK' || error?.message?.includes('Network')) {
|
||||
console.warn('API not available, using mock data');
|
||||
return mockParticipants;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getParticipantDetails(scbId: string): Promise<ParticipantInfo> {
|
||||
|
||||
165
frontend/src/utils/mockData.ts
Normal file
165
frontend/src/utils/mockData.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* Mock Data for Development
|
||||
*
|
||||
* Provides mock data when the backend API is not available.
|
||||
* This allows the frontend to function even without a running backend.
|
||||
*/
|
||||
|
||||
import type {
|
||||
NetworkHealthStatus,
|
||||
SettlementThroughput,
|
||||
GRULiquidityMetrics,
|
||||
RiskFlags,
|
||||
SCBStatus,
|
||||
ParticipantInfo,
|
||||
} from '@/types';
|
||||
|
||||
export const mockNetworkHealth: NetworkHealthStatus[] = [
|
||||
{
|
||||
subsystem: 'Settlement Engine',
|
||||
status: 'healthy',
|
||||
lastHeartbeat: new Date().toISOString(),
|
||||
latency: 12,
|
||||
errorRate: 0.001,
|
||||
},
|
||||
{
|
||||
subsystem: 'GRU Liquidity Pool',
|
||||
status: 'healthy',
|
||||
lastHeartbeat: new Date().toISOString(),
|
||||
latency: 8,
|
||||
errorRate: 0.0005,
|
||||
},
|
||||
{
|
||||
subsystem: 'CBDC Registry',
|
||||
status: 'healthy',
|
||||
lastHeartbeat: new Date().toISOString(),
|
||||
latency: 15,
|
||||
errorRate: 0.002,
|
||||
},
|
||||
{
|
||||
subsystem: 'Risk Engine',
|
||||
status: 'degraded',
|
||||
lastHeartbeat: new Date(Date.now() - 30000).toISOString(),
|
||||
latency: 45,
|
||||
errorRate: 0.01,
|
||||
},
|
||||
];
|
||||
|
||||
export const mockSettlementThroughput: SettlementThroughput = {
|
||||
txPerSecond: 1250.5,
|
||||
dailyVolume: 1250000000,
|
||||
byAssetType: {
|
||||
fiat: 450000000,
|
||||
cbdc: 320000000,
|
||||
gru: 280000000,
|
||||
ssu: 150000000,
|
||||
commodities: 50000000,
|
||||
},
|
||||
heatmap: [
|
||||
{ sourceSCB: 'US-SCB', destinationSCB: 'UK-SCB', volume: 150000000 },
|
||||
{ sourceSCB: 'EU-SCB', destinationSCB: 'US-SCB', volume: 120000000 },
|
||||
{ sourceSCB: 'UK-SCB', destinationSCB: 'EU-SCB', volume: 95000000 },
|
||||
],
|
||||
};
|
||||
|
||||
export const mockGRULiquidity: GRULiquidityMetrics = {
|
||||
currentPrice: 1.0234,
|
||||
volatility: 0.012,
|
||||
inCirculation: {
|
||||
m00: 5000000000,
|
||||
m0: 2500000000,
|
||||
m1: 1500000000,
|
||||
sr1: 800000000,
|
||||
sr2: 400000000,
|
||||
sr3: 200000000,
|
||||
},
|
||||
};
|
||||
|
||||
export const mockRiskFlags: RiskFlags = {
|
||||
high: 3,
|
||||
medium: 12,
|
||||
low: 45,
|
||||
alerts: [
|
||||
{
|
||||
id: 'alert-001',
|
||||
type: 'Liquidity Threshold',
|
||||
severity: 'high',
|
||||
description: 'GRU M0 pool below 80% threshold',
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
{
|
||||
id: 'alert-002',
|
||||
type: 'Settlement Delay',
|
||||
severity: 'medium',
|
||||
description: 'Average settlement time increased by 15%',
|
||||
timestamp: new Date(Date.now() - 3600000).toISOString(),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const mockSCBStatus: SCBStatus[] = [
|
||||
{
|
||||
scbId: 'US-SCB',
|
||||
name: 'United States Sovereign Bank',
|
||||
country: 'United States',
|
||||
bic: 'USSBUS33',
|
||||
status: 'active',
|
||||
connectivity: 'connected',
|
||||
latency: 12,
|
||||
errorRate: 0.001,
|
||||
openIncidents: 0,
|
||||
},
|
||||
{
|
||||
scbId: 'UK-SCB',
|
||||
name: 'United Kingdom Sovereign Bank',
|
||||
country: 'United Kingdom',
|
||||
bic: 'UKSBGB22',
|
||||
status: 'active',
|
||||
connectivity: 'connected',
|
||||
latency: 18,
|
||||
errorRate: 0.002,
|
||||
openIncidents: 1,
|
||||
},
|
||||
{
|
||||
scbId: 'EU-SCB',
|
||||
name: 'European Union Sovereign Bank',
|
||||
country: 'European Union',
|
||||
bic: 'EUSBBE55',
|
||||
status: 'active',
|
||||
connectivity: 'degraded',
|
||||
latency: 35,
|
||||
errorRate: 0.008,
|
||||
openIncidents: 2,
|
||||
},
|
||||
{
|
||||
scbId: 'JP-SCB',
|
||||
name: 'Japan Sovereign Bank',
|
||||
country: 'Japan',
|
||||
bic: 'JPSBJP99',
|
||||
status: 'active',
|
||||
connectivity: 'connected',
|
||||
latency: 25,
|
||||
errorRate: 0.003,
|
||||
openIncidents: 0,
|
||||
},
|
||||
];
|
||||
|
||||
export const mockParticipants: ParticipantInfo[] = mockSCBStatus.map((scb) => ({
|
||||
scbId: scb.scbId,
|
||||
name: scb.name,
|
||||
country: scb.country,
|
||||
bic: scb.bic,
|
||||
status: scb.status,
|
||||
connectivity: scb.connectivity,
|
||||
lastHeartbeat: new Date().toISOString(),
|
||||
latency: scb.latency,
|
||||
errorRate: scb.errorRate,
|
||||
}));
|
||||
|
||||
export const mockGlobalOverview = {
|
||||
networkHealth: mockNetworkHealth,
|
||||
settlementThroughput: mockSettlementThroughput,
|
||||
gruLiquidity: mockGRULiquidity,
|
||||
riskFlags: mockRiskFlags,
|
||||
scbStatus: mockSCBStatus,
|
||||
};
|
||||
Reference in New Issue
Block a user