diff --git a/frontend/public/images/pfps/default.png b/frontend/public/images/pfps/default.png index 2be60e8..d476168 100644 Binary files a/frontend/public/images/pfps/default.png and b/frontend/public/images/pfps/default.png differ diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 96deb94..e28eaee 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -14,9 +14,9 @@ import { QuickSettingsProvider } from "./context/QuickSettingsContext"; import DashboardPage from "./pages/DashboardPage"; import { Brightness } from "./context/BrightnessContext"; import LoadingScreen from "./components/Layout/LoadingScreen"; -import Following from "./pages/Following"; +import Following from "./pages/FollowingPage"; import UnsubscribePage from "./pages/UnsubscribePage"; -import Vods from "./pages/Vods"; +import VodsPage from "./pages/VodsPage"; import VodPlayer from "./pages/VodPlayer"; function App() { @@ -44,6 +44,24 @@ function App() { }); }, []); + useEffect(() => { + if (isLoggedIn) { + checkUserStatus(); + } + }, [username]); + + const checkUserStatus = async () => { + if (!username) return; + + try { + const response = await fetch(`/api/user/${username}/status`); + const data = await response.json(); + setIsLive(data.is_live); + } catch (error) { + console.error("Error checking user status:", error); + } + }; + if (isLoading) { return ; } @@ -79,8 +97,8 @@ function App() { }> } /> } /> - } /> - } /> + } /> + } /> } /> diff --git a/frontend/src/components/Stream/StreamDashboard.tsx b/frontend/src/components/Stream/StreamDashboard.tsx index 7089556..0453b0d 100644 --- a/frontend/src/components/Stream/StreamDashboard.tsx +++ b/frontend/src/components/Stream/StreamDashboard.tsx @@ -360,11 +360,9 @@ const StreamDashboard: React.FC = ({ username, userId, isL

Stream Preview

-

Video

-

List Item

= ({ streamer, extraClasses = "", const videoElement = document.createElement("video"); videoElement.classList.add("video-js", "vjs-big-play-centered", "w-full", "h-full"); videoElement.setAttribute("playsinline", "true"); + videoElement.setAttribute('preload', 'auto'); if (videoRef.current) { videoRef.current.appendChild(videoElement); } playerRef.current = videojs(videoElement, { - controls: false, + controls: true, autoplay: true, muted: false, fluid: true, diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index 3091b34..1b61526 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -11,7 +11,7 @@ interface DashboardPageProps { } const DashboardPage: React.FC = ({ tab = "dashboard" }) => { - const { username, isLive, userId, setIsLive } = useAuth(); + const { username, isLive, userId } = useAuth(); const { vods } = useVods(`/api/vods/${username}`); const [selectedTab, setSelectedTab] = useState<"dashboard" | "stream" | "vod">(tab); @@ -21,24 +21,6 @@ const DashboardPage: React.FC = ({ tab = "dashboard" }) => { dashboard: "white", }; - useEffect(() => { - if (username) { - checkUserStatus(); - } - }, [username]); - - const checkUserStatus = async () => { - if (!username) return; - - try { - const response = await fetch(`/api/user/${username}/status`); - const data = await response.json(); - setIsLive(data.is_live); - } catch (error) { - console.error("Error checking user status:", error); - } - }; - return (
diff --git a/frontend/src/pages/Following.tsx b/frontend/src/pages/FollowingPage.tsx similarity index 100% rename from frontend/src/pages/Following.tsx rename to frontend/src/pages/FollowingPage.tsx diff --git a/frontend/src/pages/Vods.tsx b/frontend/src/pages/Vods.tsx deleted file mode 100644 index 934fbc2..0000000 --- a/frontend/src/pages/Vods.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useAuth } from "../context/AuthContext"; -import { useNavigate, useParams } from "react-router-dom"; -import DynamicPageContent from "../components/Layout/DynamicPageContent"; - -interface Vod { - vod_id: number; - title: string; - datetime: string; - username: string; - category_name: string; - length: number; - views: number; -} - -const Vods: React.FC = () => { - const navigate = useNavigate(); - const { username } = useParams<{ username?: string }>(); - const { isLoggedIn } = useAuth(); - const [ownedVods, setOwnedVods] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - if (!username) return; - - const fetchVods = async () => { - try { - const response = await fetch(`/api/vods/${username}`); - if (!response.ok) throw new Error(`Failed to fetch VODs: ${response.statusText}`); - - const data = await response.json(); - setOwnedVods(data); - } catch (err) { - const errorMessage = err instanceof Error ? err.message : "Error fetching VODs."; - setError(errorMessage); - } finally { - setLoading(false); - } - }; - - fetchVods(); - }, [username]); - - if (loading) return

Loading VODs...

; - if (error) return

{error}

; - - return ( - -
-
-

{username}'s VODs

- - {/* Horizontal Scrollable VOD List */} -
- {ownedVods.length === 0 ? ( -

No VODs available.

- ) : ( - ownedVods.map((vod) => { - const thumbnailUrl = `/vods/${username}/${vod.vod_id}.png`; - - return ( -
navigate(`/stream/${username}/vods/${vod.vod_id}`)} - > - {/* Thumbnail */} - {`Thumbnail { - e.currentTarget.onerror = null; - e.currentTarget.src = "/default-thumbnail.png"; - }} - /> - - {/* Video Info */} -
-

{vod.title}

-

{username}

-

{vod.views} views

-

{new Date(vod.datetime).toLocaleString()}

-
-
- ); - }) - )} -
-
-
-
- ); -}; - -export default Vods; diff --git a/frontend/src/pages/VodsPage.tsx b/frontend/src/pages/VodsPage.tsx new file mode 100644 index 0000000..0803b83 --- /dev/null +++ b/frontend/src/pages/VodsPage.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import DynamicPageContent from "../components/Layout/DynamicPageContent"; +import { useVods } from "../hooks/useContent"; +import ListRow from "../components/Layout/ListRow"; +import LoadingScreen from "../components/Layout/LoadingScreen"; + +const VodsPage: React.FC = () => { + const { username } = useParams<{ username?: string }>(); + const { vods, isLoading, error } = useVods(`/api/vods/${username}`); + const navigate = useNavigate(); + + if (isLoading) return Loading VODs...; + if (error) return Error loading VODs: {error}; + + return ( + +
+
+

+ navigate(`/vods/${user}/${vodId}`)} + extraClasses="bg-black/50" + itemExtraClasses="w-[30vw]" + /> +
+
+
+ ); +}; + +export default VodsPage; diff --git a/web_server/database/testing_data.sql b/web_server/database/testing_data.sql index 3bd0d26..a4bae89 100644 --- a/web_server/database/testing_data.sql +++ b/web_server/database/testing_data.sql @@ -129,14 +129,6 @@ INSERT INTO streams (user_id, title, start_time, category_id) VALUES (26, 'Max Level, Max Power!', '2025-03-09 21:00:00', 26), (27, 'Final Showdown!', '2025-03-10 17:00:00', 27); --- Sample Data for vods -INSERT INTO vods (user_id, title, datetime, category_id, length, views) VALUES -(1, 'Epic Gaming Session', '2025-01-23 18:00:00', 1, 120, 500), -(2, 'Live Music Jam', '2025-01-21 20:00:00', 2, 180, 800), -(3, 'Sketching Live', '2025-01-22 15:00:00', 3, 90, 300), -(4, 'Math Made Easy', '2025-01-21 10:00:00', 4, 150, 600), -(5, 'Sports Highlights', '2025-01-19 12:00:00', 5, 210, 700); - -- Sample Data for tags INSERT INTO tags(tag_name) VALUES ('English'),