2025-08-01

This commit is contained in:
2025-08-01 13:03:58 -05:00
parent f25a69cf78
commit 1a7a6a2d50
14 changed files with 512 additions and 114 deletions

View File

@@ -1,9 +1,112 @@
import React, { useEffect, useState, useRef } from "react";
export const useWebSocketStatus = (wsUrl) => {
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
const socket = new WebSocket(wsUrl);
socket.onopen = () => setIsConnected(true);
socket.onclose = () => setIsConnected(false);
socket.onerror = () => setIsConnected(false);
return () => socket.close();
}, [wsUrl]);
return isConnected;
};
export const WebSocketStatus = ({ wsUrl }) => {
const isConnected = useWebSocketStatus(wsUrl);
return (
<div className="d-flex align-items-center gap-2">
<span
className="status-dot"
style={{
width: "10px",
height: "10px",
borderRadius: "50%",
backgroundColor: isConnected ? "green" : "red",
display: "inline-block",
}}
></span>
<span>{isConnected ? "Connected" : "Disconnected"}</span>
</div>
);
};
export const DraftAdmin = ({ draftSessionId }) => {
const [latestMessage, setLatestMessage] = useState(null);
const [connectedParticipants, setConnectedParticipants] = useState([]);
const [isConnected, setIsConnected] = useState(false);
const socketRef = useRef(null);
const wsUrl = `ws://${window.location.host}/ws/draft/session/${draftSessionId}/`;
const wsUrl = `ws://${window.location.host}/ws/draft/session/${draftSessionId}/admin`;
useEffect(() => {
socketRef.current = new WebSocket(wsUrl);
socketRef.current.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(event)
setLatestMessage(data);
if (data.type == "user.joined") {
// setConnectedParticipants =
}
else if (data.type == "draft_summary"){
console.log(data)
}
};
socketRef.current.onclose = () => {
console.warn("WebSocket connection closed.");
};
return () => {
socketRef.current.close();
};
}, [wsUrl]);
const handleStartDraft = () => {
socketRef.current.send(JSON.stringify({ type: "start.draft" }));
}
const handleRequestDraftSummary = () => {
socketRef.current.send(JSON.stringify({ type: 'request_summary' }))
}
return (
<div className="container draft-panel">
<h3>Draft Admin Panel</h3>
<WebSocketStatus wsUrl={wsUrl} />
<label>Latest Message</label>
<input
type="text"
readOnly disabled
value={latestMessage ? JSON.stringify(latestMessage) : ""}
/>
<label>Connected Particpants</label>
<input
type="text"
readOnly disabled
value={connectedParticipants ? JSON.stringify(connectedParticipants) : ""}
/>
<button onClick={handleStartDraft} className="btn btn-primary mt-2">
Start Draft
</button>
<button onClick={handleRequestDraftSummary} className="btn btn-primary mt-2">
Request status
</button>
</div>
);
};
export const DraftParticipant = ({ draftSessionId }) => {
const [latestMessage, setLatestMessage] = useState(null);
const socketRef = useRef(null);
const wsUrl = `ws://${window.location.host}/ws/draft/session/${draftSessionId}/participant`;
useEffect(() => {
socketRef.current = new WebSocket(wsUrl);
@@ -11,6 +114,9 @@ export const DraftAdmin = ({ draftSessionId }) => {
socketRef.current.onmessage = (event) => {
const data = JSON.parse(event.data);
setLatestMessage(data);
if (data.type == "draft_summary") {
console.log('draft_summary', data)
}
};
socketRef.current.onclose = () => {
@@ -27,18 +133,15 @@ export const DraftAdmin = ({ draftSessionId }) => {
}
return (
<div className="container mt-4">
<h1>Draft Admin Panel</h1>
<div className="container draft-panel">
<h3 >Draft Participant Panel</h3>
<WebSocketStatus wsUrl={wsUrl} />
<label>Latest Message</label>
<input
type="text"
className="form-control"
readOnly disabled
value={latestMessage ? JSON.stringify(latestMessage) : ""}
/>
<button onClick={handleStartDraft} className="btn btn-primary">
Start Draft
</button>
</div>
);
};

View File

@@ -3,13 +3,20 @@ console.log("Webpack HMR loaded!");
import React from "react";
import { createRoot } from "react-dom/client";
import {DraftAdmin} from './apps/draft/index.jsx'
import {DraftAdmin, DraftParticipant} from './apps/draft/index.jsx'
document.addEventListener("DOMContentLoaded", () => {
const draftApp = document.getElementById("draft-app");
const draftAdminApp = document.getElementById("draft-admin-app");
const draftApp = document.getElementById("draft-app")
if (draftApp) {
const root = createRoot(draftApp);
const draftId = draftApp.dataset.draftId
root.render(<DraftParticipant draftSessionId={draftId} />);
}
if (draftAdminApp) {
const root = createRoot(draftAdminApp);
const draftId = draftAdminApp.dataset.draftId
root.render(<DraftAdmin draftSessionId={draftId} />);
}
});
});

View File

@@ -15,4 +15,18 @@
font-family: "Graphique";
font-size: x-large;
}
}
.draft-panel {
@extend .mt-4 ;
@extend .border ;
@extend .rounded-2 ;
@extend .p-2;
@extend .pt-1;
label {
@extend .form-label;
}
input {
@extend .form-control;
}
}