Skip to content

Commit d8d3fb1

Browse files
committed
feat(frontend): harden banks API and instrument status telemetry
1 parent 6b4e472 commit d8d3fb1

6 files changed

Lines changed: 21 additions & 26 deletions

File tree

Dechat/dex_with_fiat_frontend/src/components/OfflineStatusBanner.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2-
import { renderHook, act } from '@testing-library/react';
2+
import { act } from '@testing-library/react';
33
import { render, screen, waitFor } from '@testing-library/react';
44
import OfflineStatusBanner from './OfflineStatusBanner';
55
import * as offlineMessageQueue from '@/lib/offlineMessageQueue';

Dechat/dex_with_fiat_frontend/src/components/OfflineStatusBanner.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use client';
22

3-
import { useEffect, useState, useCallback, useRef } from 'react';
3+
import { useEffect, useState, useRef } from 'react';
44
import { AlertTriangle, WifiOff } from 'lucide-react';
55
import { useOnlineStatus } from '@/hooks/useOnlineStatus';
66
import { useToast } from '@/hooks/useToast';
77
import { offlineStatusToastSchema } from '@/lib/offlineStatusSchema';
8-
import { subscribeToQueuedMessageCount, setQueuedMessageCount, getQueuedMessageCount } from '@/lib/offlineMessageQueue';
8+
import { subscribeToQueuedMessageCount } from '@/lib/offlineMessageQueue';
99

1010
/**
1111
* Offline Status Banner Component
@@ -18,7 +18,6 @@ export default function OfflineStatusBanner() {
1818
const { addToast } = useToast();
1919
const [showBanner, setShowBanner] = useState(false);
2020
const [isLoading, setIsLoading] = useState(true);
21-
const [pendingCount, setPendingCount] = useState(0);
2221
const [optimisticPendingCount, setOptimisticPendingCount] = useState(0);
2322
const [isReconnecting, setIsReconnecting] = useState(false);
2423
const previousOnlineState = useRef<boolean>(true);
@@ -33,23 +32,10 @@ export default function OfflineStatusBanner() {
3332

3433
useEffect(() => {
3534
return subscribeToQueuedMessageCount((count) => {
36-
setPendingCount(count);
3735
setOptimisticPendingCount(count);
3836
});
3937
}, []);
4038

41-
// Optimistic update: increment pending count immediately when message is queued
42-
const optimisticallyIncrementPending = useCallback(() => {
43-
setOptimisticPendingCount((prev: number) => prev + 1);
44-
setQueuedMessageCount(getQueuedMessageCount() + 1);
45-
}, []);
46-
47-
// Optimistic update: decrement pending count immediately when message is sent
48-
const optimisticallyDecrementPending = useCallback(() => {
49-
setOptimisticPendingCount((prev: number) => Math.max(0, prev - 1));
50-
setQueuedMessageCount(Math.max(0, getQueuedMessageCount() - 1));
51-
}, []);
52-
5339
useEffect(() => {
5440
// Optimistic UI: Show banner immediately when going offline
5541
if (!isOnline && previousOnlineState.current) {

Dechat/dex_with_fiat_frontend/src/hooks/useStatusTelemetry.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ class MockEventSource {
1515
onerror: (() => void) | null = null;
1616
close = vi.fn();
1717

18-
constructor(_url: string) {
18+
constructor(url: string) {
19+
void url;
1920
MockEventSource.latest = this;
2021
}
2122
}

Dechat/dex_with_fiat_frontend/src/lib/aiAssistant.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,7 @@ describe('AIAssistant abort signal support', () => {
240240

241241
expect(toastAddMock).toHaveBeenCalled();
242242
consoleErrorSpy.mockRestore();
243-
244-
243+
});
245244
});
246245

247246
/**

Dechat/dex_with_fiat_frontend/src/lib/apiSchemas.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ describe('apiSchemas - Request Retry with Exponential Backoff', () => {
4646
.mockRejectedValueOnce(new TypeError('Failed to fetch'))
4747
.mockResolvedValue('success');
4848

49-
const startTime = Date.now();
5049
const promise = withRetry(fn, { initialDelayMs: 100, maxRetries: 2 });
5150

5251
// Advance timers for first retry

Dechat/dex_with_fiat_frontend/src/lib/apiSchemas.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ export interface RetryConfig {
5353
retryableErrors?: (error: unknown) => boolean;
5454
}
5555

56+
interface HttpError extends Error {
57+
status?: number;
58+
response?: Response;
59+
}
60+
5661
/**
5762
* Default retry configuration
5863
*/
@@ -140,8 +145,12 @@ export async function withRetry<T>(
140145
// Check if error is retryable
141146
const isRetryableError = mergedConfig.retryableErrors(error);
142147
const isRetryableStatus =
143-
error instanceof Response &&
144-
mergedConfig.retryableStatusCodes.includes(error.status);
148+
error instanceof Response
149+
? mergedConfig.retryableStatusCodes.includes(error.status)
150+
: error instanceof Error &&
151+
mergedConfig.retryableStatusCodes.includes(
152+
(error as HttpError).status ?? 0,
153+
);
145154

146155
if (!isRetryableError && !isRetryableStatus) {
147156
throw error; // Non-retryable error, throw immediately
@@ -175,9 +184,10 @@ export async function fetchWithRetry(
175184

176185
if (!response.ok) {
177186
// Throw error to trigger retry for non-OK responses
178-
const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
179-
(error as any).status = response.status;
180-
(error as any).response = response;
187+
const error: HttpError = Object.assign(
188+
new Error(`HTTP ${response.status}: ${response.statusText}`),
189+
{ status: response.status, response },
190+
);
181191
throw error;
182192
}
183193

0 commit comments

Comments
 (0)