diff --git a/components/wallet/ui/OfflineBanner.tsx b/components/wallet/ui/OfflineBanner.tsx
index 60f3979..462e5ab 100644
--- a/components/wallet/ui/OfflineBanner.tsx
+++ b/components/wallet/ui/OfflineBanner.tsx
@@ -1,25 +1,35 @@
'use client';
import useOffline from '@/hooks/useOffline';
-import { WifiOff } from 'lucide-react';
+import { WifiOff, Wifi } from 'lucide-react';
/**
* OfflineBanner — Component to display network status fallback.
*/
const OfflineBanner = () => {
- const { isOnline } = useOffline();
+ const { isOnline, showBackOnline } = useOffline();
- if (isOnline) return null;
+ if (isOnline && !showBackOnline) return null;
return (
-
-
+
+ {showBackOnline ? (
+
+ ) : (
+
+ )}
- You are currently offline.{' '}
-
- Transactions are disabled until connection is restored.
-
+ {showBackOnline ? (
+ 'Back Online!'
+ ) : (
+ <>
+ You are currently offline.{' '}
+
+ Transactions are disabled until connection is restored.
+
+ >
+ )}
diff --git a/hooks/__tests__/useOffline.test.ts b/hooks/__tests__/useOffline.test.ts
index c639163..e80018e 100644
--- a/hooks/__tests__/useOffline.test.ts
+++ b/hooks/__tests__/useOffline.test.ts
@@ -2,6 +2,8 @@ import { renderHook, act } from '@testing-library/react';
import useOffline from '@/hooks/useOffline';
import { networkService } from '@/services/networkService';
+jest.useFakeTimers();
+
jest.mock('@/services/networkService', () => ({
networkService: {
getIsOnline: jest.fn(),
@@ -14,12 +16,17 @@ describe('useOffline', () => {
beforeEach(() => {
jest.clearAllMocks();
+ jest.useFakeTimers();
(networkService.subscribe as jest.Mock).mockImplementation((cb) => {
subscribeCallback = cb;
return jest.fn(); // Unsubscribe mock
});
});
+ afterEach(() => {
+ jest.useRealTimers();
+ });
+
it('should initialize with the current network status', () => {
(networkService.getIsOnline as jest.Mock).mockReturnValue(true);
const { result } = renderHook(() => useOffline());
@@ -38,12 +45,21 @@ describe('useOffline', () => {
});
expect(result.current.isOnline).toBe(false);
+ expect(result.current.showBackOnline).toBe(false);
act(() => {
subscribeCallback(true);
});
+ expect(result.current.isOnline).toBe(false);
+ expect(result.current.showBackOnline).toBe(true);
+
+ act(() => {
+ jest.advanceTimersByTime(2000);
+ });
+
expect(result.current.isOnline).toBe(true);
+ expect(result.current.showBackOnline).toBe(false);
});
it('should cleanup subscription on unmount', () => {
diff --git a/hooks/useOffline.tsx b/hooks/useOffline.tsx
index 3a1e0b6..22638cc 100644
--- a/hooks/useOffline.tsx
+++ b/hooks/useOffline.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useState, useRef } from 'react';
import { networkService } from '@/services/networkService';
/**
@@ -8,20 +8,43 @@ const useOffline = () => {
const [isOnline, setIsOnline] = useState
(
networkService.getIsOnline()
);
+ const [showBackOnline, setShowBackOnline] = useState(false);
+ const timeoutRef = useRef(null);
useEffect(() => {
- // eslint-disable-next-line react-hooks/set-state-in-effect
setIsOnline(networkService.getIsOnline());
const unsubscribe = networkService.subscribe((status) => {
- setIsOnline(status);
+ if (status) {
+ setShowBackOnline(true);
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current);
+ }
+ timeoutRef.current = setTimeout(() => {
+ setShowBackOnline(false);
+ setIsOnline(true);
+ }, 2000);
+ } else {
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current);
+ timeoutRef.current = null;
+ }
+ setShowBackOnline(false);
+ setIsOnline(false);
+ }
});
- return () => unsubscribe();
+ return () => {
+ unsubscribe();
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current);
+ }
+ };
}, []);
return {
isOnline,
+ showBackOnline,
};
};
diff --git a/jest.config.ts b/jest.config.ts
index b33a0fa..d061a79 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -10,7 +10,11 @@ const config: Config = {
'^.+\\.(ts|tsx)$': [
'ts-jest',
{
- tsconfig: '/tsconfig.jest.json',
+ tsconfig: {
+ jsx: 'react-jsx',
+ moduleResolution: 'node',
+ ignoreDeprecations: '5.0',
+ },
},
],
},