Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a43df3a
fix: Add debug log in service worker installation method
jaygiang Feb 23, 2025
6881ccf
feat: Add network status handler and event listeners to Application
jaygiang Feb 23, 2025
4a280fa
feat: Add useOfflineStatus hook import to Home component
jaygiang Feb 23, 2025
0a8b229
feat: Add offline status warning to Home page using useOfflineStatus …
jaygiang Feb 23, 2025
35320c9
feat: Add network online status detection method to application confi…
jaygiang Feb 23, 2025
e4b2b65
feat: Add useApplication hook with ApplicationContext
jaygiang Feb 23, 2025
99d4dd4
fix: Export ApplicationContext from react-radfish package
jaygiang Feb 23, 2025
d2d4bed
fix: Remove duplicate useOfflineStatus export in hooks index
jaygiang Feb 23, 2025
95c160d
feat: Improve network connectivity check with navigator status and Gi…
jaygiang Feb 24, 2025
a306bf3
fix: Remove unnecessary console.log in service worker installation
jaygiang Feb 24, 2025
689570c
feat: Add initial network status check on application startup
jaygiang Feb 24, 2025
3e0e079
Remove console log
jaygiang Feb 24, 2025
d1dc947
refactor: Remove ApplicationContext and network configuration from index
jaygiang Feb 24, 2025
d9dbe21
fix: remove duplicate useApplication context
jaygiang Feb 25, 2025
07ca6eb
fix: remove test alert from react-query example
jaygiang Feb 25, 2025
8b52a4e
Fix: remove console.log
jaygiang Feb 25, 2025
d08b576
feat: update packages to handle fallback and flapping
jaygiang Mar 5, 2025
99585be
feat: Update enhanced network status example
jaygiang Mar 5, 2025
7d0c836
Update readme for network status
jaygiang Mar 5, 2025
cf3444c
update: Remove network flapping
jaygiang Mar 7, 2025
41de1a9
fix: Change fetch method to request method
jaygiang Mar 8, 2025
5d177ca
Merge branch 'main' into 660-user-defined-status-handler
thgaskell Aug 12, 2025
0de5e24
fix merge conflict
thgaskell Aug 12, 2025
acb871e
Merge branch 'main' into 660-user-defined-status-handler
jaygiang Sep 11, 2025
a8d0bad
Check if networkHandler is a function before calling
thgaskell Sep 11, 2025
fe5b8cf
Merge branch 'main' into 660-user-defined-status-handler
JCopeland-PIFSC Sep 17, 2025
714129f
fix: event dispatch in react-radfish unit tests
thgaskell Sep 23, 2025
7381f00
Update depenendency lock file
thgaskell Sep 29, 2025
5abdf16
Correctly add dev dependencies for ci environment
thgaskell Sep 29, 2025
e34c068
chore(release): bump @nmfs-radfish/react-radfish to 1.1.0-rc.0
github-actions[bot] Sep 29, 2025
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
123 changes: 104 additions & 19 deletions examples/network-status/README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,127 @@
# Network Status Example

This example demonstrates how to detect a user's network connectivity. If the user is offline, the built-in status indicator will display `Offline ❌`. If online, it will show `Online ✅`.
This example demonstrates network status handling with sophisticated features for modern web applications that need to be resilient to network issues.

The `useOfflineStatus` hook provides an `isOffline` utility that detects the user's network connectivity. It uses the `navigator` browser API. Refer to the [MDN Navigator Docs](https://developer.mozilla.org/en-US/docs/Web/API/Navigator) for limitations.
## Key Features

- **Real-time Network Status Detection**: Monitors online/offline state using browser APIs and custom network checks
- **Resilient Fetching**: Implements automatic retries with exponential backoff for failed network requests
- **Request Timeout Control**: Configurable timeout settings to prevent hanging requests
- **Fallback URLs**: Automatic redirection to alternative endpoints when primary endpoints fail
- **Custom Network Testing Tools**: Tools to simulate various network conditions for testing

Learn more about RADFish examples at the official [documentation](https://nmfs-radfish.github.io/radfish/developer-documentation/examples-and-templates#examples). Refer to the [RADFish GitHub repo](https://nmfs-radfish.github.io/radfish/) for more information and code samples.

## Preview

This example will render as shown in this screenshot:
This example renders as shown in this screenshot:

![Network Status](./src/assets/network-status.png)

## Steps
## Implementation

### 1. Import Required Dependencies
### 1. Configuring Network Features

Import the following libraries in the `App.jsx` file:
Set up the Application with network handling options:

```jsx
import React, { useEffect } from "react";
import { useOfflineStatus } from "@nmfs-radfish/react-radfish";
import { Alert } from "@trussworks/react-uswds";
const app = new Application({
network: {
// Custom timeout in milliseconds (default is 30000)
timeout: 5000,

// Fallback URLs to use when primary endpoints fail
fallbackUrls: {
"https://nonexistent-endpoint.example.com": "https://jsonplaceholder.typicode.com/users"
},

// Optional custom network status handler
setIsOnline: async (networkInfo, callback) => {
// Custom logic to determine network status
try {
const response = await fetch("https://api.github.com/users", {
method: "HEAD",
signal: AbortSignal.timeout(3000)
});
callback(response.ok);
} catch (error) {
callback(false);
}
}
}
});
```

### 2. Use `useOfflineStatus` to Access Network State
### 2. Using Network Status Features

Within the `HomePage` component, use `useOfflineStatus` to retrieve the `isOffline` property, which indicates whether the application is currently offline:
Access the network status features through hooks:

```jsx
const HomePage = () => {
const { isOffline } = useOfflineStatus(); // Retrieve the isOffline state

return (
<div className="grid-container">
<h1>Network Status Example</h1>
<h3 className="header-body">Network Status: {isOffline ? "Offline ❌" : "Online ✅"}</h3>
</div>
);
const { isOffline } = useOfflineStatus();
const app = useApplication();

// Network status tag
const getNetworkStatusTag = () => {
if (isOffline) {
return <Tag className="bg-error">Offline</Tag>;
} else {
return <Tag className="bg-success">Online</Tag>;
}
};

// Using fetch with retry and fallback capabilities
const fetchWithRetry = async () => {
try {
const response = await app.fetchWithRetry(
"https://nonexistent-endpoint.example.com",
{},
{
retries: 2,
retryDelay: 1000,
exponentialBackoff: true,
}
);
const data = await response.json();
// Handle successful response
} catch (error) {
// Handle failure after all retries
}
};

return (
<div>
<div>Current Status: {getNetworkStatusTag()}</div>
<Button onClick={fetchWithRetry}>Test Fetch with Retry</Button>
</div>
);
};
```

## Testing with Browser DevTools

To fully test the network resilience features, you can use browser DevTools:

### Viewing Console Logs

1. Open DevTools in your browser:
- **Chrome/Edge**: Press F12 or right-click and select "Inspect"
- **Firefox**: Press F12 or right-click and select "Inspect Element"
- **Safari**: Enable "Developer Tools" in preferences, then press Option+Command+I

2. Go to the "Console" tab to view logs:
- Network status changes appear as color-coded logs
- Retry attempts are logged with blue backgrounds

### Simulating Offline/Online States

1. In DevTools, go to the "Network" tab
2. Look for the "Online" dropdown (may appear as "No throttling" in some browsers)
3. Select "Offline" to simulate a disconnected state
4. Return to "Online" or "No throttling" to restore connectivity

### Testing Fetch with Retry and Fallbacks

1. Click the "Test Fetch with Retry" button while watching the Console
2. You'll see logs of retry attempts and eventual success or failure
3. If using a fallback URL, you'll see the fallback request after the primary URL fails
4 changes: 2 additions & 2 deletions examples/network-status/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Application } from "@nmfs-radfish/react-radfish";
import { GridContainer } from "@trussworks/react-uswds";
import HomePage from "./pages/Home";

function App() {
function App({ app }) {
return (
<Application>
<Application application={app}>
<GridContainer>
<Router>
<Routes>
Expand Down
36 changes: 36 additions & 0 deletions examples/network-status/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,39 @@ body {
.padding-4 {
padding: 16px;
}

/* Remove bullet points from cards and grid items */
.usa-card ul {
list-style: none;
padding-left: 0;
}

.grid-col {
list-style-type: none;
}

.grid-row {
list-style: none;
padding-left: 0;
padding-top: 10px;
}

/* Equal height cards and layout fixes */
.usa-card {
height: 100%;
display: flex;
flex-direction: column;
}

.usa-card .usa-card__body {
display: flex;
flex-direction: column;
height: 100%;
flex: 1 1 auto;
}

.usa-card .usa-button {
height: auto;
min-height: 40px;
margin-bottom: 0.5rem;
}
61 changes: 60 additions & 1 deletion examples/network-status/src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,76 @@ import { ErrorBoundary } from "@nmfs-radfish/react-radfish";

const root = ReactDOM.createRoot(document.getElementById("root"));

// Initialize the radfish application with network features
const app = new Application({
serviceWorker: {
url: "/service-worker.js",
},

network: {
// Health check configuration
health: {
// Endpoint URL for health checks
endpointUrl: "https://api.github.com/users",
// Custom timeout in milliseconds (default is 30000)
timeout: 5000
},

// Fallback URLs to use when primary endpoints fail
fallbackUrls: {
"https://nonexistent-endpoint.example.com": "https://jsonplaceholder.typicode.com/users"
},

// Optional custom network status handler
setIsOnline: async (networkInfo, callback) => {
console.log("Checking network with custom handler...");

try {
// Test connectivity to a reliable endpoint
// We perform a small HEAD request with a short timeout
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);

const response = await fetch("https://api.github.com/users", {
method: "HEAD",
signal: controller.signal
});

clearTimeout(timeoutId);
console.log("Network check result:", response.ok);
callback(response.ok);
} catch (error) {
// Any errors indicate we're probably offline
console.log("Network status check failed:", error.message);
callback(false);
}
}
}
});

// Listen for all network-related events
app.addEventListener("online", (event) => {
console.log("%c NETWORK ONLINE ", "background: #4CAF50; color: #fff; font-weight: bold; padding: 4px;");
});

app.addEventListener("offline", (event) => {
console.log("%c NETWORK OFFLINE ", "background: #F44336; color: #fff; font-weight: bold; padding: 4px;");
});

app.addEventListener("networkRetry", (event) => {
console.warn("%c NETWORK RETRY ", "background: #3F51B5; color: #fff; font-weight: bold; padding: 4px;", event.detail);

// Show an alert for first retry attempt
if (event.detail.attempt === 1) {
alert(`Network retry initiated! Will retry ${event.detail.maxRetries} times.`);
}
});

app.on("ready", () => {
root.render(
<ErrorBoundary>
<React.StrictMode>
<App />
<App app={app} />
</React.StrictMode>
</ErrorBoundary>
);
Expand Down
Loading