Add movie detail API and enhance draft admin/participant UI

- Introduced `/api/movie/<id>/detail` endpoint returning TMDB data for a movie.
- Moved draft detail fetching logic into `common/utils.js` for reuse.
- Updated Draft Admin panel:
  - Added phase navigation buttons with bootstrap icons.
  - Improved layout with refresh and status controls.
- Updated Draft Participant panel:
  - Added movie pool display with links to movie details.
- Added bootstrap-icons stylesheet and corresponding SCSS styles for new UI.
This commit is contained in:
2025-08-08 15:12:40 -05:00
parent 9b6b3391e6
commit 24700071ed
8 changed files with 186 additions and 101 deletions

View File

@@ -4,6 +4,7 @@ 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([])
@@ -48,37 +49,23 @@ const ParticipantList = ({ socket, participants, draftOrder }) => {
)
}
const DraftPhaseDisplay = ({ draftPhase }) => {
const DraftPhaseDisplay = ({ draftPhase, nextPhaseHandler, prevPhaseHandler }) => {
return (
<div className="draft-phase-container">
<label>Phase</label>
<ol>
{
DraftPhases.map((p) => (
<li key={p} className={p === draftPhase ? "current-phase" : ""}>
<span>{p}</span>
</li>
))
}
</ol>
</div>
)
}
const DraftOrder = ({ socket, draftOrder }) => {
console.log("in component", draftOrder)
return (
<div>
<label>Draft Order</label>
<ol>
{
draftOrder.map((p) => (
<li key={p}>
{p}
</li>
))
}
</ol>
<div className="d-flex">
<div className="change-phase"><button onClick={prevPhaseHandler}><i className="bi bi-chevron-left"></i></button></div>
<ol>
{
DraftPhases.map((p) => (
<li key={p} className={p === draftPhase ? "current-phase" : ""}>
<span>{p}</span>
</li>
))
}
</ol>
<div className="change-phase"><button onClick={nextPhaseHandler}><i className="bi bi-chevron-right"></i></button></div>
</div>
</div>
)
}
@@ -93,34 +80,16 @@ export const DraftAdmin = ({ draftSessionId }) => {
console.log(socket)
useEffect(() => {
async function fetchDraftDetails(draftSessionId) {
fetch(`/api/draft/${draftSessionId}/`)
.then((response) => {
if (response.ok) {
return response.json()
}
else {
throw new Error()
}
})
.then((data) => {
console.log(data)
setParticipants(data.participants)
})
.catch((err) => {
console.error("Error fetching draft details", err)
})
}
fetchDraftDetails(draftSessionId)
.then((data) => {
console.log("Fetched draft data", data)
setParticipants(data.participants)
})
}, [])
useEffect(() => {
if (!socket) return;
else {
console.warn("socket doesn't exist")
}
console.log('socket created', socket)
const handleMessage = (event) => {
const message = JSON.parse(event.data)
@@ -153,12 +122,29 @@ export const DraftAdmin = ({ draftSessionId }) => {
};
}, [socket]);
const handlePhaseChange = (destinationPhase) => {
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") {
}
if (!destination) {return}
socket.send(
JSON.stringify(
{ type: DraftMessage.REQUEST.PHASE_CHANGE, "origin": draftPhase, "destination": destinationPhase }
{ type: DraftMessage.REQUEST.PHASE_CHANGE, origin, destination }
)
);
)
}
@@ -170,29 +156,25 @@ export const DraftAdmin = ({ draftSessionId }) => {
)
}
return (
<div className="container draft-panel admin">
<h3>Draft Admin Panel</h3>
<WebSocketStatus socket={socket} />
{/* <MessageLogger socket={socketRef.current} /> */}
<div className="d-flex justify-content-between border-bottom mb-2 p-1">
<h3>Draft Panel</h3>
<div className="d-flex gap-1">
<WebSocketStatus socket={socket} />
<button onClick={() => handleRequestDraftSummary()} className="btn btn-small btn-light">
<i className="bi bi-arrow-clockwise"></i>
</button>
</div>
</div>
<ParticipantList
socket={socket}
participants={participants}
draftOrder={draftOrder}
/>
<DraftPhaseDisplay draftPhase={draftPhase}></DraftPhaseDisplay>
<button onClick={() => handlePhaseChange(DraftPhase.DETERMINE_ORDER)} className="btn btn-primary mt-2 me-2">
Determine Draft Order
</button>
<button onClick={() => handleRequestDraftSummary()} className="btn btn-primary mt-2">
Request status
</button>
<button onClick={() => handlePhaseChange(DraftPhase.NOMINATION)} className="btn btn-primary mt-2 me-2">
Go to Nominate
</button>
<DraftPhaseDisplay draftPhase={draftPhase} nextPhaseHandler={ ()=>{handlePhaseChange('next')}} prevPhaseHandler= {() => {handlePhaseChange('previous')}}></DraftPhaseDisplay>
</div>
);
};