summaryrefslogtreecommitdiff
path: root/gui/src/components/WsWidget.tsx
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-10-06 10:13:39 +0700
committerpolwex <polwex@sortug.com>2025-10-06 10:13:39 +0700
commit8751ba26ebf7b7761b9e237f2bf3453623dd1018 (patch)
treedc37f12b3fd9b1a1e7a1b54a51c80697f37a04e8 /gui/src/components/WsWidget.tsx
parent6704650dcfccf609ccc203308df9004e0b511bb6 (diff)
added frontend WS connection for demonstration purposes
Diffstat (limited to 'gui/src/components/WsWidget.tsx')
-rw-r--r--gui/src/components/WsWidget.tsx123
1 files changed, 123 insertions, 0 deletions
diff --git a/gui/src/components/WsWidget.tsx b/gui/src/components/WsWidget.tsx
new file mode 100644
index 0000000..75c773d
--- /dev/null
+++ b/gui/src/components/WsWidget.tsx
@@ -0,0 +1,123 @@
+import { useWebSocket } from "@/hooks/useWs";
+import { useState } from "react";
+
+type WidgetProps = {
+ url: string;
+ protocols?: string | string[];
+};
+
+export default function WebSocketWidget({ url, protocols }: WidgetProps) {
+ const {
+ status,
+ retryCount,
+ lastMessage,
+ error,
+ bufferedAmount,
+ send,
+ reconnectNow,
+ close,
+ } = useWebSocket({
+ url,
+ protocols,
+ onMessage: (ev) => {
+ // Example: auto reply to pings
+ console.log(ev.data, "ws event");
+ if (
+ typeof ev.data === "string" &&
+ // ev.data.toLowerCase().includes("ping")
+ ev.data.toLowerCase().trim() == "ping"
+ ) {
+ try {
+ console.log("sending pong");
+ send("pong");
+ } catch {}
+ }
+ },
+ });
+
+ const [outbound, setOutbound] = useState("");
+
+ return (
+ <div className="w-full max-w-xl mx-auto p-4 grid gap-3">
+ <header className="flex items-center justify-between">
+ <h1 className="text-xl font-semibold">WebSocketWidget</h1>
+ <span className="text-sm px-2 py-1 rounded-full border">
+ {status.toUpperCase()} {retryCount ? `(retry ${retryCount})` : ""}
+ </span>
+ </header>
+
+ <div className="text-sm text-gray-600">
+ <div>
+ <b>URL:</b> {url}
+ </div>
+ <div>
+ <b>Buffered:</b> {bufferedAmount} bytes
+ </div>
+ {error && (
+ <div className="text-red-600">
+ <b>Error:</b>{" "}
+ {"message" in error
+ ? (error as any).message
+ : String(error.type || "error")}
+ </div>
+ )}
+ </div>
+
+ <div className="p-3 rounded-2xl border bg-gray-50 min-h-[4rem] font-mono text-sm break-words">
+ <div className="opacity-70">Last message:</div>
+ <div>
+ {lastMessage
+ ? typeof lastMessage.data === "string"
+ ? lastMessage.data
+ : "(binary)"
+ : "—"}
+ </div>
+ </div>
+
+ <form
+ className="flex gap-2"
+ onSubmit={(e) => {
+ e.preventDefault();
+ if (!outbound) return;
+ send(outbound);
+ setOutbound("");
+ }}
+ >
+ <input
+ className="flex-1 px-3 py-2 rounded-xl border"
+ placeholder="Type message…"
+ value={outbound}
+ onChange={(e) => setOutbound(e.target.value)}
+ />
+ <button type="submit" className="px-3 py-2 rounded-xl border">
+ Send
+ </button>
+ </form>
+
+ <div className="flex gap-2">
+ <button className="px-3 py-2 rounded-xl border" onClick={reconnectNow}>
+ Reconnect
+ </button>
+ <button className="px-3 py-2 rounded-xl border" onClick={() => close()}>
+ Close
+ </button>
+ </div>
+
+ <details className="mt-2">
+ <summary className="cursor-pointer">Usage</summary>
+ <pre className="text-xs bg-gray-100 p-2 rounded-xl overflow-auto">
+ {`import WebSocketWidget from "./WebSocketWidget";
+
+export default function App() {
+ return (
+ <div className="p-6">
+ <WebSocketWidget url="wss://echo.websocket.events" />
+ </div>
+ );
+}
+`}
+ </pre>
+ </details>
+ </div>
+ );
+}