95 lines
2.9 KiB
TypeScript
95 lines
2.9 KiB
TypeScript
import React, { useState, useEffect } from "react";
|
|
import { Box, Typography, CircularProgress, Paper, LinearProgress } from "@mui/material";
|
|
import { ReadyState } from "react-use-websocket";
|
|
|
|
interface ConnectionStatusProps {
|
|
readyState: ReadyState;
|
|
reconnectAttempt?: number;
|
|
}
|
|
|
|
const ConnectionStatus: React.FC<ConnectionStatusProps> = ({ readyState, reconnectAttempt = 0 }) => {
|
|
const [countdown, setCountdown] = useState(0);
|
|
|
|
// Start countdown when connection is closed and we're attempting to reconnect
|
|
useEffect(() => {
|
|
if (readyState === ReadyState.CLOSED && reconnectAttempt > 0) {
|
|
setCountdown(5);
|
|
const interval = setInterval(() => {
|
|
setCountdown((prev) => {
|
|
if (prev <= 1) {
|
|
clearInterval(interval);
|
|
return 0;
|
|
}
|
|
return prev - 1;
|
|
});
|
|
}, 1000);
|
|
|
|
return () => clearInterval(interval);
|
|
}
|
|
}, [readyState, reconnectAttempt]);
|
|
|
|
const getConnectionStatusText = () => {
|
|
switch (readyState) {
|
|
case ReadyState.CONNECTING:
|
|
return reconnectAttempt > 0 ? `Reconnecting... (attempt ${reconnectAttempt})` : "Connecting to server...";
|
|
case ReadyState.OPEN:
|
|
return "Connected";
|
|
case ReadyState.CLOSING:
|
|
return "Disconnecting...";
|
|
case ReadyState.CLOSED:
|
|
if (reconnectAttempt > 0 && countdown > 0) {
|
|
return `Connection lost. Retrying in ${countdown}s... (attempt ${reconnectAttempt})`;
|
|
}
|
|
return reconnectAttempt > 0 ? "Reconnecting..." : "Disconnected";
|
|
case ReadyState.UNINSTANTIATED:
|
|
return "Initializing...";
|
|
default:
|
|
return "Unknown connection state";
|
|
}
|
|
};
|
|
|
|
const getConnectionColor = () => {
|
|
switch (readyState) {
|
|
case ReadyState.OPEN:
|
|
return "success.main";
|
|
case ReadyState.CONNECTING:
|
|
return "info.main";
|
|
case ReadyState.CLOSED:
|
|
return "error.main";
|
|
case ReadyState.CLOSING:
|
|
return "warning.main";
|
|
default:
|
|
return "text.secondary";
|
|
}
|
|
};
|
|
|
|
const shouldShowProgress =
|
|
readyState === ReadyState.CONNECTING || (readyState === ReadyState.CLOSED && reconnectAttempt > 0);
|
|
|
|
return (
|
|
<Paper
|
|
sx={{
|
|
p: 2,
|
|
m: 2,
|
|
width: "fit-content",
|
|
backgroundColor: readyState === ReadyState.CLOSED ? "#ffebee" : "background.paper",
|
|
}}
|
|
>
|
|
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
|
|
{shouldShowProgress && <CircularProgress size={20} />}
|
|
<Typography variant="h6" color={getConnectionColor()}>
|
|
{getConnectionStatusText()}
|
|
</Typography>
|
|
</Box>
|
|
|
|
{readyState === ReadyState.CLOSED && reconnectAttempt > 0 && countdown > 0 && (
|
|
<Box sx={{ mt: 2, width: "100%" }}>
|
|
<LinearProgress variant="determinate" value={((5 - countdown) / 5) * 100} sx={{ borderRadius: 1 }} />
|
|
</Box>
|
|
)}
|
|
</Paper>
|
|
);
|
|
};
|
|
|
|
export { ConnectionStatus };
|