diff --git a/api/urls.py b/api/urls.py index 59fb7de..d4ffe9f 100644 --- a/api/urls.py +++ b/api/urls.py @@ -1,9 +1,18 @@ from rest_framework.routers import DefaultRouter -from .views import UserViewSet, MovieViewSet, DraftSessionViewSet +from .views import UserViewSet, MovieViewSet, DraftSessionViewSet, movie_detail +from django.urls import path router = DefaultRouter() router.register(r'users', UserViewSet, basename='user') router.register(r'movies', MovieViewSet, basename='movie') router.register(r'draft', DraftSessionViewSet, basename='draft') -urlpatterns = router.urls \ No newline at end of file + +urlpatterns = [ + *router.urls, + path( + "movie//detail", + movie_detail, + name="movie-detail" + ), +] \ No newline at end of file diff --git a/api/views.py b/api/views.py index 100a889..e193e4c 100644 --- a/api/views.py +++ b/api/views.py @@ -4,6 +4,9 @@ from django.contrib.auth import get_user_model from boxofficefantasy.models import Movie from draft.models import DraftSession, DraftPick from django.shortcuts import get_object_or_404 +from rest_framework.response import Response +from boxofficefantasy.integrations.tmdb import get_tmdb_movie_by_imdb +from rest_framework.decorators import api_view from django.db.models import Prefetch @@ -57,4 +60,34 @@ class DraftSessionViewSet(viewsets.ReadOnlyModelViewSet): "movies", Prefetch("draft_picks", queryset=DraftPick.objects.select_related("winner", "movie")), ) - ) \ No newline at end of file + ) + +@api_view(["GET"]) +def movie_detail(request, movie_id): + """ + GET /api/movie/{movie_id}/detail + Returns TMDB movie details + and the movie is in that session. + """ + # Lookup DraftSession by hashid or pk + # draft_session = get_object_or_404(DraftSession, hashid=draft_session_id) + + # # Ensure requesting user is a participant + # if request.user not in draft_session.participants.all(): + # return Response({"detail": "Not authorized for this draft session."}, + # status=status.HTTP_403_FORBIDDEN) + + # # Get movie in this session + movie = get_object_or_404(Movie, pk=movie_id) + + # Call TMDB integration + tmdb_data = get_tmdb_movie_by_imdb(movie.imdb_id) + if not tmdb_data: + return Response({"detail": "Movie details not found."}, + status=404) + + return Response({ + "id": movie.id, + "title": movie.title, + "tmdb": tmdb_data + }) \ No newline at end of file diff --git a/boxofficefantasy/templates/base.dj.html b/boxofficefantasy/templates/base.dj.html index bf3726c..e624ee1 100644 --- a/boxofficefantasy/templates/base.dj.html +++ b/boxofficefantasy/templates/base.dj.html @@ -7,6 +7,7 @@ rel="stylesheet" href="https://cdn.datatables.net/2.3.2/css/dataTables.bootstrap5.css" /> + {% if DEBUG %} {% else %} diff --git a/frontend/src/apps/draft/admin/DraftAdmin.jsx b/frontend/src/apps/draft/admin/DraftAdmin.jsx index 2e179f5..715c24a 100644 --- a/frontend/src/apps/draft/admin/DraftAdmin.jsx +++ b/frontend/src/apps/draft/admin/DraftAdmin.jsx @@ -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 (
-
    - { - DraftPhases.map((p) => ( -
  1. - {p} -
  2. - )) - } -
-
- ) -} - -const DraftOrder = ({ socket, draftOrder }) => { - console.log("in component", draftOrder) - return ( -
- -
    - { - draftOrder.map((p) => ( -
  1. - {p} -
  2. - )) - } -
+
+
+
    + { + DraftPhases.map((p) => ( +
  1. + {p} +
  2. + )) + } +
+
+
) } @@ -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 (
-

Draft Admin Panel

- - {/* */} +
+

Draft Panel

+
+ + +
+
- - - - + + {handlePhaseChange('next')}} prevPhaseHandler= {() => {handlePhaseChange('previous')}}>
); }; \ No newline at end of file diff --git a/frontend/src/apps/draft/common/utils.js b/frontend/src/apps/draft/common/utils.js new file mode 100644 index 0000000..26bdac4 --- /dev/null +++ b/frontend/src/apps/draft/common/utils.js @@ -0,0 +1,29 @@ +export async function fetchDraftDetails(draftSessionId) { + return fetch(`/api/draft/${draftSessionId}/`) + .then((response) => { + if (response.ok) { + return response.json() + } + else { + throw new Error() + } + }) + .catch((err) => { + console.error("Error fetching draft details", err) + }) + } + +export async function fetchMovieDetails(draftSessionId) { + return fetch(`/api/draft/${draftSessionId}/movie/`) + .then((response) => { + if (response.ok) { + return response.json() + } + else { + throw new Error() + } + }) + .catch((err) => { + console.error("Error fetching draft details", err) + }) + } \ No newline at end of file diff --git a/frontend/src/apps/draft/participant/DraftParticipant.jsx b/frontend/src/apps/draft/participant/DraftParticipant.jsx index 5e50dfd..156da54 100644 --- a/frontend/src/apps/draft/participant/DraftParticipant.jsx +++ b/frontend/src/apps/draft/participant/DraftParticipant.jsx @@ -4,13 +4,40 @@ 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" + +const DraftMoviePool = ({ movies }) => { + return ( +
+ +
+ ) +} export const DraftParticipant = ({ draftSessionId }) => { const socket = useWebSocket(); - const [connectedParticipants, setConnectedParticipants] = useState([]); + const [participants, setParticipants] = useState([]); const [draftPhase, setDraftPhase] = useState(); + const [movies, setMovies] = useState([]); console.log(socket) + useEffect(() => { + fetchDraftDetails(draftSessionId) + .then((data) => { + console.log("Fetched draft data", data) + setMovies(data.movies) + }) + }, []) + + useEffect(() => { if (!socket) return; else { @@ -60,27 +87,12 @@ export const DraftParticipant = ({ draftSessionId }) => { return (
-

Draft Admin Panel

- - {/* */} - - - - - - +
+

Draft Panel

+ +
+ +
); }; \ No newline at end of file diff --git a/frontend/src/index.js b/frontend/src/index.js index 6f74ec8..c81362e 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -15,7 +15,7 @@ if (draftPartipantRoot) { const wsUrl = `ws://${window.location.host}/ws/draft/session/${draftSessionId}/participant`; createRoot(draftPartipantRoot).render( - + ); } diff --git a/frontend/src/scss/styles.scss b/frontend/src/scss/styles.scss index 8a31595..2eaab41 100644 --- a/frontend/src/scss/styles.scss +++ b/frontend/src/scss/styles.scss @@ -55,14 +55,32 @@ .danger { @extend .bg-danger; } +.draft-panel { +} .draft-phase-container { label { @extend .fs-3; } - ol, ul { + .change-phase { + + + button { + @extend .btn; + @extend .btn-light; + @extend .p-0; + height: 100%; + } + } + + ol, + ul { + --bs-list-group-active-bg: var(--bs-primary-bg-subtle); + --bs-list-group-active-color: $dark; @extend .list-group; @extend .list-group-horizontal; + @extend .ms-1; + @extend .me-1; li { @extend .list-group-item; @extend .p-1; @@ -70,18 +88,23 @@ @extend .pe-2; &.current-phase { - @extend .active + @extend .active; } } } } -.participant-list-container { +.participant-list-container, +.movie-pool-container { max-width: 575.98px; label { @extend .fs-3; } @extend .list-group; + ol, + ul { + @extend .p-0; + } ol { @extend .list-group-numbered; } @@ -94,9 +117,5 @@ @extend .me-auto; @extend .ps-1; } - &::marker{ - content:">"; - color:green; - } } }