Refactor draft messaging to unified enum-based protocol
- Replaced scattered message strings with `DraftMessage` `StrEnum` and numeric `DraftPhase` `IntEnum` for clear, centralized definitions. - Added Python→JS constants sync via `scripts/generate_js_constants.py` to ensure backend/frontend parity. - Refactored WebSocket consumers to use `broadcast.*` and `direct.message` handlers with `_dispatch_broadcast` for consistent event delivery. - Enhanced `DraftStateManager` to store `draft_index` and explicitly manage `connected_participants`. - Added colored logging config in settings for improved debugging. - Frontend: split UI into `ParticipantList` and `DraftMoviePool`, extracted message handlers (`handleDraftStatusMessages`, `handleUserIdentifyMessages`), and updated components to use new message/phase enums.
This commit is contained in:
@@ -1,53 +1,13 @@
|
||||
// DraftAdmin.jsx
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { useWebSocket } from "../WebSocketContext.jsx";
|
||||
import { WebSocketStatus } from "../common/WebSocketStatus.jsx";
|
||||
import { DraftMessage, DraftPhases, DraftPhase } from '../constants.js';
|
||||
import { fetchDraftDetails } from "../common/utils.js"
|
||||
|
||||
const ParticipantList = ({ socket, participants, draftOrder }) => {
|
||||
const [connectedParticipants, setConnectedParticipants] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
const handleMessage = async ({ data }) => {
|
||||
const message = JSON.parse(data)
|
||||
const { type, payload } = message
|
||||
console.log('socket changed', message)
|
||||
if (payload?.connected_participants) {
|
||||
const { connected_participants } = payload
|
||||
setConnectedParticipants(connected_participants)
|
||||
}
|
||||
}
|
||||
socket.addEventListener("message", handleMessage)
|
||||
return () => {
|
||||
socket.removeEventListener("message", handleMessage)
|
||||
}
|
||||
}, [socket])
|
||||
|
||||
const ListTag = draftOrder.length > 0 ? "ol" : "ul"
|
||||
console.log
|
||||
const listItems = draftOrder.length > 0 ? draftOrder.map(d => participants.find(p => p.username == d)) : participants
|
||||
import { ParticipantList } from "../common/ParticipantList.jsx";
|
||||
import { DraftMessage, DraftPhase, DraftPhaseLabel, DraftPhasesOrdered } from '../constants.js';
|
||||
import { fetchDraftDetails, isEmptyObject, handleDraftStatusMessages, handleUserIdentifyMessages } from "../common/utils.js"
|
||||
import { DraftMoviePool } from "../common/DraftMoviePool.jsx"
|
||||
|
||||
|
||||
return (
|
||||
<div className="participant-list-container">
|
||||
<label>Particpants</label>
|
||||
<ListTag className="participant-list">
|
||||
{listItems.map((p, i) => (
|
||||
<li key={i}>
|
||||
<span>{p?.full_name}</span>
|
||||
<div
|
||||
className={
|
||||
`ms-2 stop-light ${connectedParticipants.includes(p?.username) ? "success" : "danger"}`
|
||||
}
|
||||
></div>
|
||||
</li>
|
||||
))}
|
||||
</ListTag>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const DraftPhaseDisplay = ({ draftPhase, nextPhaseHandler, prevPhaseHandler }) => {
|
||||
return (
|
||||
@@ -57,14 +17,14 @@ const DraftPhaseDisplay = ({ draftPhase, nextPhaseHandler, prevPhaseHandler }) =
|
||||
<div className="change-phase"><button onClick={prevPhaseHandler}><i className="bi bi-chevron-left"></i></button></div>
|
||||
<ol>
|
||||
{
|
||||
DraftPhases.map((p) => (
|
||||
DraftPhasesOrdered.map((p) => (
|
||||
<li key={p} className={p === draftPhase ? "current-phase" : ""}>
|
||||
<span>{p}</span>
|
||||
<span>{DraftPhaseLabel[p]}</span>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ol>
|
||||
<div className="change-phase"><button onClick={nextPhaseHandler}><i className="bi bi-chevron-right"></i></button></div>
|
||||
<div className="change-phase"><button onClick={nextPhaseHandler}><i className="bi bi-chevron-right"></i></button></div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -72,86 +32,84 @@ const DraftPhaseDisplay = ({ draftPhase, nextPhaseHandler, prevPhaseHandler }) =
|
||||
|
||||
export const DraftAdmin = ({ draftSessionId }) => {
|
||||
const socket = useWebSocket();
|
||||
const [connectedParticipants, setConnectedParticipants] = useState([]);
|
||||
const [draftDetails, setDraftDetails] = useState();
|
||||
const [participants, setParticipants] = React.useState([]);
|
||||
const [draftPhase, setDraftPhase] = useState();
|
||||
const [draftOrder, setDraftOrder] = useState([]);
|
||||
console.log(socket)
|
||||
const [draftState, setDraftState] = useState({})
|
||||
const [currentUser, setCurrentUser] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetchDraftDetails(draftSessionId)
|
||||
.then((data) => {
|
||||
console.log("Fetched draft data", data)
|
||||
setParticipants(data.participants)
|
||||
setDraftDetails(data)
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
useEffect(()=>{
|
||||
if (!socket) return;
|
||||
const openHandler = (event)=>{
|
||||
console.log('Websocket Opened')
|
||||
}
|
||||
const closeHandler = (event)=>{
|
||||
console.log('Websocket Closed')
|
||||
}
|
||||
socket.addEventListener('open', openHandler );
|
||||
socket.addEventListener('close', closeHandler );
|
||||
return ()=>{
|
||||
socket.removeEventListener('open', openHandler );
|
||||
socket.removeEventListener('close', closeHandler );
|
||||
}
|
||||
}, [socket])
|
||||
|
||||
useEffect(() => {
|
||||
if (!socket) return;
|
||||
|
||||
const handleMessage = (event) => {
|
||||
const message = JSON.parse(event.data)
|
||||
const { type, payload } = message;
|
||||
console.log(type, event)
|
||||
if (!payload) return
|
||||
if (type == DraftMessage.REQUEST.JOIN_PARTICIPANT) {
|
||||
console.log('join request', data)
|
||||
}
|
||||
if (payload.phase) {
|
||||
console.log('phase_change')
|
||||
setDraftPhase(payload.phase)
|
||||
}
|
||||
if (payload.draft_order) {
|
||||
console.log('draft_order', payload.draft_order)
|
||||
setDraftOrder(payload.draft_order)
|
||||
}
|
||||
}
|
||||
|
||||
socket.addEventListener('message', handleMessage);
|
||||
|
||||
socket.onclose = (event) => {
|
||||
console.log('Websocket Closed')
|
||||
socket = null;
|
||||
}
|
||||
|
||||
const draftStatusMessageHandler = (event) => handleDraftStatusMessages(event, setDraftState)
|
||||
const userIdentifyMessageHandler = (event) => handleUserIdentifyMessages(event, setCurrentUser)
|
||||
socket.addEventListener('message', draftStatusMessageHandler );
|
||||
socket.addEventListener('message', userIdentifyMessageHandler );
|
||||
|
||||
return () => {
|
||||
socket.removeEventListener('message', handleMessage)
|
||||
socket.close();
|
||||
socket.removeEventListener('message', draftStatusMessageHandler)
|
||||
socket.removeEventListener('message', userIdentifyMessageHandler );
|
||||
};
|
||||
}, [socket]);
|
||||
|
||||
const handlePhaseChange = (target) => {
|
||||
let destination
|
||||
const origin = draftPhase
|
||||
if (target == "next") {
|
||||
console.log(DraftPhase)
|
||||
console.log("phase to be changed", origin, target, DraftPhase.WAITING)
|
||||
if (origin == "waiting"){
|
||||
destination = DraftPhase.DETERMINE_ORDER
|
||||
} else if (origin == "determine_order"){
|
||||
destination = DraftPhase.NOMINATION
|
||||
}
|
||||
}
|
||||
else if (target=="previous") {
|
||||
|
||||
const origin = draftState.phase
|
||||
const originPhaseIndex = DraftPhasesOrdered.findIndex(i => i == origin)
|
||||
console.log('origin phase index', originPhaseIndex)
|
||||
if (target == "next" && originPhaseIndex < DraftPhasesOrdered.length) {
|
||||
destination = DraftPhasesOrdered[originPhaseIndex + 1]
|
||||
}
|
||||
|
||||
if (!destination) {return}
|
||||
else if (target == "previous" && originPhaseIndex > 0) {
|
||||
destination = DraftPhasesOrdered[originPhaseIndex - 1]
|
||||
}
|
||||
console.log(destination)
|
||||
socket.send(
|
||||
JSON.stringify(
|
||||
{ type: DraftMessage.REQUEST.PHASE_CHANGE, origin, destination }
|
||||
{ type: DraftMessage.PHASE_CHANGE_REQUEST, origin, destination }
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
|
||||
const handleStartDraft = () => {
|
||||
|
||||
}
|
||||
|
||||
const handleAdvanceDraft = () => {
|
||||
socket.send(
|
||||
JSON.stringify(
|
||||
{ type: DraftMessage.DRAFT_INDEX_ADVANCE_REQUEST }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const handleRequestDraftSummary = () => {
|
||||
socket.send(
|
||||
JSON.stringify(
|
||||
{ type: DraftMessage.REQUEST.DRAFT_STATUS }
|
||||
{ type: DraftMessage.STATUS_SYNC_REQUEST }
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -169,12 +127,14 @@ export const DraftAdmin = ({ draftSessionId }) => {
|
||||
</div>
|
||||
|
||||
<ParticipantList
|
||||
socket={socket}
|
||||
participants={participants}
|
||||
draftOrder={draftOrder}
|
||||
draftState={draftState}
|
||||
draftDetails={draftDetails}
|
||||
isAdmin={true}
|
||||
/>
|
||||
<button onClick={handleAdvanceDraft} className="btn btn-primary">Advance Draft</button>
|
||||
<DraftMoviePool draftDetails={draftDetails}></DraftMoviePool>
|
||||
|
||||
<DraftPhaseDisplay draftPhase={draftPhase} nextPhaseHandler={ ()=>{handlePhaseChange('next')}} prevPhaseHandler= {() => {handlePhaseChange('previous')}}></DraftPhaseDisplay>
|
||||
<DraftPhaseDisplay draftPhase={draftState.phase} nextPhaseHandler={() => { handlePhaseChange('next') }} prevPhaseHandler={() => { handlePhaseChange('previous') }}></DraftPhaseDisplay>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user