From 5be499d0ada5669b0a0b6a9d96bcb9cb1ef4ad45 Mon Sep 17 00:00:00 2001 From: jlightner Date: Sat, 4 Apr 2026 06:12:10 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Wired=20ChapterReview=20into=20App=20ro?= =?UTF-8?q?utes=20(/creator/chapters,=20/creator/=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - "frontend/src/App.tsx" - "frontend/src/pages/CreatorDashboard.tsx" - "frontend/src/pages/ChapterReview.tsx" - "frontend/src/pages/ChapterReview.module.css" GSD-Task: S06/T03 --- frontend/src/App.tsx | 1 + frontend/src/pages/ChapterReview.module.css | 48 +++++++++++++ frontend/src/pages/ChapterReview.tsx | 75 ++++++++++++++++++++- frontend/src/pages/CreatorDashboard.tsx | 10 +-- 4 files changed, 126 insertions(+), 8 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 248d533..09d5681 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -199,6 +199,7 @@ function AppShell() { }>} /> }>} /> }>} /> + }>} /> }>} /> {/* Fallback */} diff --git a/frontend/src/pages/ChapterReview.module.css b/frontend/src/pages/ChapterReview.module.css index c9529f5..63a7636 100644 --- a/frontend/src/pages/ChapterReview.module.css +++ b/frontend/src/pages/ChapterReview.module.css @@ -285,3 +285,51 @@ align-items: flex-start; } } + +/* ── Video Picker ─────────────────────────────────────────────────────────── */ + +.videoPickerList { + display: flex; + flex-direction: column; + gap: 0.5rem; + margin-top: 1rem; +} + +.videoPickerCard { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.875rem 1rem; + border-radius: 8px; + background: var(--surface-2, #1e293b); + border: 1px solid var(--border, #334155); + color: var(--text-primary, #e2e8f0); + text-decoration: none; + transition: background 0.15s, border-color 0.15s; +} + +.videoPickerCard:hover { + background: var(--surface-3, #2d3a4d); + border-color: var(--accent, #22d3ee); +} + +.videoPickerIcon { + width: 20px; + height: 20px; + flex-shrink: 0; + color: var(--text-secondary, #94a3b8); +} + +.videoPickerInfo { + display: flex; + flex-direction: column; + min-width: 0; +} + +.videoPickerName { + font-size: 0.9rem; + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/frontend/src/pages/ChapterReview.tsx b/frontend/src/pages/ChapterReview.tsx index f583dbe..b289f6f 100644 --- a/frontend/src/pages/ChapterReview.tsx +++ b/frontend/src/pages/ChapterReview.tsx @@ -1,5 +1,5 @@ import { useCallback, useEffect, useRef, useState } from "react"; -import { useParams } from "react-router-dom"; +import { Link, useParams } from "react-router-dom"; import WaveSurfer from "wavesurfer.js"; import RegionsPlugin from "wavesurfer.js/dist/plugins/regions.esm.js"; import { SidebarNav } from "./CreatorDashboard"; @@ -14,6 +14,7 @@ import { type ChapterPatch, type VideoDetail, } from "../api/videos"; +import { fetchConsentList, type VideoConsentRead } from "../api/consent"; import { useDocumentTitle } from "../hooks/useDocumentTitle"; import styles from "./ChapterReview.module.css"; @@ -49,12 +50,84 @@ function regionColor(status: string): string { } } +/* ── Video Picker (shown when no videoId in URL) ───────────────────────────── */ + +function VideoPicker() { + const [videos, setVideos] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + let cancelled = false; + fetchConsentList() + .then((res) => { + if (!cancelled) setVideos(res.items); + }) + .catch((err) => { + if (!cancelled) + setError(err instanceof ApiError ? err.detail : "Failed to load videos"); + }) + .finally(() => { + if (!cancelled) setLoading(false); + }); + return () => { cancelled = true; }; + }, []); + + return ( +
+ +
+

Chapter Review

+

Select a video to review its chapters

+ + {loading &&
Loading videos…
} + {!loading && error &&
{error}
} + {!loading && !error && videos.length === 0 && ( +
+

No Videos

+

You don't have any videos yet.

+
+ )} + {!loading && !error && videos.length > 0 && ( +
+ {videos.map((v) => ( + + + + + +
+ {v.video_filename} +
+ + ))} +
+ )} +
+
+ ); +} + /* ── Main component ────────────────────────────────────────────────────────── */ export default function ChapterReview() { const { videoId } = useParams<{ videoId: string }>(); useDocumentTitle("Chapter Review"); + // If no videoId in URL, show the video picker + if (!videoId) return ; + + return ; +} + +/* ── Detail view (has a videoId) ───────────────────────────────────────────── */ + +function ChapterReviewDetail({ videoId }: { videoId: string }) { + const [chapters, setChapters] = useState([]); const [video, setVideo] = useState(null); const [loading, setLoading] = useState(true); diff --git a/frontend/src/pages/CreatorDashboard.tsx b/frontend/src/pages/CreatorDashboard.tsx index de1fefc..87398e8 100644 --- a/frontend/src/pages/CreatorDashboard.tsx +++ b/frontend/src/pages/CreatorDashboard.tsx @@ -24,17 +24,13 @@ function SidebarNav() { Dashboard - + - Content - + Chapters +