UPDATE: Move user status fetch to App.tsx;

REFACTOR: Rename `Vods` & `Following` to `VodsPage` & `FollowingPage` and improve structure;
UPDATE: Change default profile picture;
REFACTOR: Remove VOD testing data;
UPDATE: Change `VideoPlayer` atrributes;
This commit is contained in:
Chris-1010
2025-03-06 22:38:13 +00:00
parent d8bf1411c7
commit 555aedffcb
9 changed files with 61 additions and 134 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 139 KiB

View File

@@ -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 <LoadingScreen />;
}
@@ -79,8 +97,8 @@ function App() {
<Route path="/results" element={<ResultsPage />}></Route>
<Route path="/404" element={<NotFoundPage />} />
<Route path="/user/:username/following" element={<Following />} />
<Route path="/user/:username/vods" element={<Vods />} />
<Route path="/stream/:username/vods/:vod_id" element={<VodPlayer />} />
<Route path="/vods/:username" element={<VodsPage />} />
<Route path="/vods/:username/:vod_id" element={<VodPlayer />} />
<Route path="*" element={<Navigate to="/404" replace />} />
</Routes>
</BrowserRouter>

View File

@@ -360,11 +360,9 @@ const StreamDashboard: React.FC<StreamDashboardProps> = ({ username, userId, isL
<h2 className="text-center text-2xl font-bold text-white mb-4">Stream Preview</h2>
<div className="flex flex-col gap-4 bg-gray-800 rounded-lg p-4 w-full h-fit flex-grow justify-around">
<div className="flex flex-col">
<p className="text-white text-center pb-4">Video</p>
<VideoPlayer streamer={username ?? undefined} extraClasses="border border-white" onStreamDetected={setStreamDetected} />
</div>
<div className="flex flex-col">
<p className="text-white text-center">List Item</p>
<StreamListItem
id={1}
title={streamData.title || "Stream Title"}

View File

@@ -32,12 +32,13 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ 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,

View File

@@ -11,7 +11,7 @@ interface DashboardPageProps {
}
const DashboardPage: React.FC<DashboardPageProps> = ({ 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<DashboardPageProps> = ({ 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 (
<DynamicPageContent className="flex flex-col min-h-screen bg-gradient-radial from-purple-600 via-blue-900 to-black">
<div id="dashboard" className="flex flex-col justify-evenly items-center h-full text-white">

View File

@@ -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<Vod[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(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 <p className="text-center">Loading VODs...</p>;
if (error) return <p className="text-center text-red-500">{error}</p>;
return (
<DynamicPageContent className="h-full">
<div className="mt-[3em] w-screen flex justify-center">
<div
id="vods-container"
className="w-[96vw] bg-slate-50/35 rounded-lg p-4 overflow-x-auto whitespace-nowrap scrollbar-hide pb-7"
>
<h1 className="text-2xl font-bold text-center mb-4">{username}'s VODs</h1>
{/* Horizontal Scrollable VOD List */}
<div className="flex space-x-4 overflow-x-auto scrollbar-hide">
{ownedVods.length === 0 ? (
<p className="text-center w-full">No VODs available.</p>
) : (
ownedVods.map((vod) => {
const thumbnailUrl = `/vods/${username}/${vod.vod_id}.png`;
return (
<div
key={vod.vod_id}
className="w-[30.8vw] h-[30vh] flex-shrink-0 bg-gray-800 text-white rounded-lg p-3 cursor-pointer hover:bg-gray-700 transition"
onClick={() => navigate(`/stream/${username}/vods/${vod.vod_id}`)}
>
{/* Thumbnail */}
<img
src={thumbnailUrl}
alt={`Thumbnail for ${vod.title}`}
className="w-full h-[150px] object-cover rounded-md"
onError={(e) => {
e.currentTarget.onerror = null;
e.currentTarget.src = "/default-thumbnail.png";
}}
/>
{/* Video Info */}
<div className="mt-2">
<h2 className="text-lg font-bold">{vod.title}</h2>
<p className="text-sm text-gray-300">{username}</p>
<p className="text-sm text-gray-400">{vod.views} views</p>
<p className="text-xs text-gray-400">{new Date(vod.datetime).toLocaleString()}</p>
</div>
</div>
);
})
)}
</div>
</div>
</div>
</DynamicPageContent>
);
};
export default Vods;

View File

@@ -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 <LoadingScreen>Loading VODs...</LoadingScreen>;
if (error) return <LoadingScreen>Error loading VODs: {error}</LoadingScreen>;
return (
<DynamicPageContent className="h-full">
<div className="mt-[3em] flex justify-center">
<div id="vods-container" className="w-[96vw] bg-slate-50/35 rounded-lg p-4 overflow-x-auto whitespace-nowrap scrollbar-hide pb-7">
<h1 className="text-2xl font-bold text-center mb-4"></h1>
<ListRow
type="vod"
title={`${username}'s VODs`}
items={vods}
wrap={true}
onItemClick={(user, vodId) => navigate(`/vods/${user}/${vodId}`)}
extraClasses="bg-black/50"
itemExtraClasses="w-[30vw]"
/>
</div>
</div>
</DynamicPageContent>
);
};
export default VodsPage;

View File

@@ -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'),