Add nomination submission and bidding start workflow

- Added `BID_START_REQUEST` and `NOMINATION_SUBMIT_REQUEST` handling in backend consumers.
- Extended draft state to include `current_movie` and `bids` cache keys.
- Updated frontend to:
  - Allow participants to nominate movies when it's their turn.
  - Enable admins to start bidding for the nominated movie.
  - Highlight the current nominated movie and the current user.
- Synced state updates across clients via WebSocket events.
This commit is contained in:
2025-08-10 16:30:27 -05:00
parent 28c98afc32
commit b08a345563
10 changed files with 151 additions and 28 deletions

View File

@@ -3,17 +3,53 @@ import React, { useEffect, useState } from "react";
import { useWebSocket } from "../WebSocketContext.jsx";
import { WebSocketStatus } from "../common/WebSocketStatus.jsx";
import { DraftMessage, DraftPhases} from '../constants.js';
import { fetchDraftDetails } from "../common/utils.js";
import { DraftMessage, DraftPhases } from '../constants.js';
import { fetchDraftDetails, handleUserIdentifyMessages, isEmptyObject } from "../common/utils.js";
import { DraftMoviePool } from "../common/DraftMoviePool.jsx";
import { ParticipantList } from "../common/ParticipantList.jsx";
import { handleDraftStatusMessages } from '../common/utils.js'
const NominateMenu = ({socket, draftState, draftDetails, currentUser}) => {
if (!socket || isEmptyObject(draftDetails) || isEmptyObject(draftState)) return;
const currentDrafter = draftState.draft_order[draftState.draft_index]
if (currentUser != currentDrafter) return;
const {movies} = draftDetails
const requestNomination = (event) => {
event.preventDefault()
const formData = new FormData(event.target)
socket.send(JSON.stringify({
type: DraftMessage.NOMINATION_SUBMIT_REQUEST,
payload: {
id: formData.get('movie'),
user: currentUser
}
}))
}
return (
<div>
<label>Nominate</label>
{draftState.draft_order[draftState.draft_index]}
<div className="d-flex">
<form onSubmit={requestNomination}>
<select className="form-control" name="movie">
{movies.map(m=>(
<option key={m.id} value={m.id}>{m.title}</option>
))}
</select>
<button className="btn btn-primary">Nominate</button>
</form>
</div>
</div>
)
}
export const DraftParticipant = ({ draftSessionId }) => {
const socket = useWebSocket();
const [draftState, setDraftState] = useState({});
const [draftDetails, setDraftDetails] = useState({});
const [currentUser, setCurrentUser] = useState(null);
const [movies, setMovies] = useState([]);
console.log(socket)
@@ -27,7 +63,7 @@ export const DraftParticipant = ({ draftSessionId }) => {
})
}, [draftSessionId])
useEffect(()=>{
useEffect(() => {
if (!socket) return;
socket.onclose = (event) => {
console.log('Websocket Closed')
@@ -37,12 +73,14 @@ export const DraftParticipant = ({ draftSessionId }) => {
useEffect(() => {
if (!socket) return;
const handler = (event) => handleDraftStatusMessages(event, setDraftState)
socket.addEventListener('message', handler );
const draftStatusMessageHandler = (event) => handleDraftStatusMessages(event, setDraftState)
const userIdentifyMessageHandler = (event) => handleUserIdentifyMessages(event, setCurrentUser)
socket.addEventListener('message', draftStatusMessageHandler);
socket.addEventListener('message', userIdentifyMessageHandler);
return () => {
socket.addEventListener('message', handler );
socket.close();
socket.removeEventListener('message', draftStatusMessageHandler)
socket.removeEventListener('message', userIdentifyMessageHandler);
};
}, [socket]);
@@ -53,11 +91,13 @@ export const DraftParticipant = ({ draftSessionId }) => {
<WebSocketStatus socket={socket} />
</div>
<ParticipantList
currentUser={currentUser}
draftState={draftState}
draftDetails={draftDetails}
isAdmin={false}
/>
<DraftMoviePool draftDetails={draftDetails}></DraftMoviePool>
<DraftMoviePool isParticipant={true} draftDetails={draftDetails} draftState={draftState}></DraftMoviePool>
<NominateMenu socket={socket} currentUser={currentUser} draftState={draftState} draftDetails={draftDetails}></NominateMenu>
</div>
);
};