Merge branch 'main' of https://github.com/john-david3/cs3305-team11
This commit is contained in:
@@ -30,7 +30,7 @@ const DynamicPageContent: React.FC<DynamicPageContentProps> = ({
|
|||||||
id="content"
|
id="content"
|
||||||
className={`min-w-[850px] ${
|
className={`min-w-[850px] ${
|
||||||
showSideBar ? "w-[85vw] translate-x-[15vw]" : "w-[100vw]"
|
showSideBar ? "w-[85vw] translate-x-[15vw]" : "w-[100vw]"
|
||||||
} items-start pb-[12vh] transition-all duration-[500ms] ease-in-out ${contentClassName}`}
|
} items-start transition-all duration-[500ms] ease-in-out ${contentClassName}`}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const Navbar: React.FC<NavbarProps> = ({ variant = "default" }) => {
|
|||||||
const { showAuthModal, setShowAuthModal } = useAuthModal();
|
const { showAuthModal, setShowAuthModal } = useAuthModal();
|
||||||
const { showSideBar } = useSidebar();
|
const { showSideBar } = useSidebar();
|
||||||
const { showQuickSettings, setShowQuickSettings } = useQuickSettings();
|
const { showQuickSettings, setShowQuickSettings } = useQuickSettings();
|
||||||
|
const [justToggled, setJustToggled] = React.useState(false);
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
console.log("Logging out...");
|
console.log("Logging out...");
|
||||||
@@ -38,6 +39,8 @@ const Navbar: React.FC<NavbarProps> = ({ variant = "default" }) => {
|
|||||||
|
|
||||||
const handleQuickSettings = () => {
|
const handleQuickSettings = () => {
|
||||||
setShowQuickSettings(!showQuickSettings);
|
setShowQuickSettings(!showQuickSettings);
|
||||||
|
setJustToggled(true);
|
||||||
|
setTimeout(() => setJustToggled(false), 750);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Keyboard shortcut to toggle sidebar
|
// Keyboard shortcut to toggle sidebar
|
||||||
@@ -65,43 +68,43 @@ const Navbar: React.FC<NavbarProps> = ({ variant = "default" }) => {
|
|||||||
>
|
>
|
||||||
{isLoggedIn && window.innerWidth > 900 && <Sidebar />}
|
{isLoggedIn && window.innerWidth > 900 && <Sidebar />}
|
||||||
<Logo variant={variant} />
|
<Logo variant={variant} />
|
||||||
{/* Login / Logout Button */}
|
{/* Login / Logout Button */}
|
||||||
<Button
|
<Button
|
||||||
extraClasses={`absolute top-[2vh] ${
|
extraClasses={`absolute top-[2vh] ${
|
||||||
showSideBar
|
showSideBar
|
||||||
? "left-[16vw] duration-[0.5s]"
|
? "left-[16vw] duration-[0.5s]"
|
||||||
: "left-[20px] duration-[1s]"
|
: "left-[20px] duration-[1s]"
|
||||||
} text-[1rem] flex items-center flex-nowrap z-[99]`}
|
} text-[1rem] flex items-center flex-nowrap z-[99]`}
|
||||||
onClick={() => (isLoggedIn ? handleLogout() : setShowAuthModal(true))}
|
onClick={() => (isLoggedIn ? handleLogout() : setShowAuthModal(true))}
|
||||||
>
|
>
|
||||||
{isLoggedIn ? (
|
{isLoggedIn ? (
|
||||||
<>
|
<>
|
||||||
<LogOutIcon className="h-15 w-15 mr-1" />
|
<LogOutIcon className="h-15 w-15 mr-1" />
|
||||||
Logout
|
Logout
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<LogInIcon className="h-15 w-15 mr-1" />
|
<LogInIcon className="h-15 w-15 mr-1" />
|
||||||
Login / Register
|
Login / Register
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
{/* Quick Settings Sidebar */}
|
{/* Quick Settings Sidebar */}
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
extraClasses={`absolute group text-[1rem] top-[2vh] ${
|
extraClasses={`absolute group text-[1rem] top-[2vh] ${
|
||||||
showQuickSettings ? "right-[21vw]" : "right-[20px]"
|
showQuickSettings ? "right-[21vw]" : "right-[20px]"
|
||||||
} cursor-pointer`}
|
} cursor-pointer`}
|
||||||
onClick={() => handleQuickSettings()}
|
onClick={() => handleQuickSettings()}
|
||||||
toggled={showQuickSettings}
|
toggled={showQuickSettings}
|
||||||
>
|
>
|
||||||
<SettingsIcon className="h-[2vw] w-[2vw]" />
|
<SettingsIcon className="h-[2vw] w-[2vw]" />
|
||||||
{showQuickSettings && (
|
{!showQuickSettings && !justToggled && (
|
||||||
<small className="absolute flex items-center top-0 mr-4 right-0 h-full w-full my-auto group-hover:right-full opacity-0 group-hover:opacity-100 text-white transition-all delay-200">
|
<small className="absolute flex items-center top-0 mr-4 right-0 h-full w-full my-auto group-hover:right-full opacity-0 group-hover:opacity-100 text-white transition-all delay-200">
|
||||||
Press Q
|
Press Q
|
||||||
</small>
|
</small>
|
||||||
)}
|
)}
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
<QuickSettings />
|
<QuickSettings />
|
||||||
|
|
||||||
{variant != "no-searchbar" && <SearchBar />}
|
{variant != "no-searchbar" && <SearchBar />}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const Sidebar: React.FC<SideBarProps> = ({ extraClasses = "" }) => {
|
|||||||
const { username, isLoggedIn } = useAuth();
|
const { username, isLoggedIn } = useAuth();
|
||||||
const [followedStreamers, setFollowedStreamers] = useState<Streamer[]>([]);
|
const [followedStreamers, setFollowedStreamers] = useState<Streamer[]>([]);
|
||||||
const [followedCategories, setFollowedCategories] = useState<Category[]>([]);
|
const [followedCategories, setFollowedCategories] = useState<Category[]>([]);
|
||||||
|
const [justToggled, setJustToggled] = useState(false);
|
||||||
|
|
||||||
// Fetch followed streamers
|
// Fetch followed streamers
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -46,6 +47,8 @@ const Sidebar: React.FC<SideBarProps> = ({ extraClasses = "" }) => {
|
|||||||
|
|
||||||
const handleSideBar = () => {
|
const handleSideBar = () => {
|
||||||
setShowSideBar(!showSideBar);
|
setShowSideBar(!showSideBar);
|
||||||
|
setJustToggled(true);
|
||||||
|
setTimeout(() => setJustToggled(false), 750);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Keyboard shortcut to toggle sidebar
|
// Keyboard shortcut to toggle sidebar
|
||||||
@@ -98,7 +101,7 @@ const Sidebar: React.FC<SideBarProps> = ({ extraClasses = "" }) => {
|
|||||||
>
|
>
|
||||||
<SidebarIcon className="h-[2vw] w-[2vw]" />
|
<SidebarIcon className="h-[2vw] w-[2vw]" />
|
||||||
|
|
||||||
{showSideBar && (
|
{!showSideBar && !justToggled && (
|
||||||
<small className="absolute flex items-center top-0 ml-4 left-0 h-full w-full my-auto group-hover:left-full opacity-0 group-hover:opacity-100 text-white transition-all delay-200">
|
<small className="absolute flex items-center top-0 ml-4 left-0 h-full w-full my-auto group-hover:left-full opacity-0 group-hover:opacity-100 text-white transition-all delay-200">
|
||||||
Press S
|
Press S
|
||||||
</small>
|
</small>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const ChatPanel: React.FC<ChatPanelProps> = ({
|
|||||||
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
||||||
const [inputMessage, setInputMessage] = useState("");
|
const [inputMessage, setInputMessage] = useState("");
|
||||||
const chatContainerRef = useRef<HTMLDivElement>(null);
|
const chatContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [justToggled, setJustToggled] = useState(false);
|
||||||
|
|
||||||
// Join chat room when component mounts
|
// Join chat room when component mounts
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -114,6 +115,8 @@ const ChatPanel: React.FC<ChatPanelProps> = ({
|
|||||||
|
|
||||||
const toggleChat = () => {
|
const toggleChat = () => {
|
||||||
setShowChat(!showChat);
|
setShowChat(!showChat);
|
||||||
|
setJustToggled(true);
|
||||||
|
setTimeout(() => setJustToggled(false), 750);
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendChat = () => {
|
const sendChat = () => {
|
||||||
@@ -147,11 +150,11 @@ const ChatPanel: React.FC<ChatPanelProps> = ({
|
|||||||
{/* Toggle Button for Chat */}
|
{/* Toggle Button for Chat */}
|
||||||
<button
|
<button
|
||||||
onClick={toggleChat}
|
onClick={toggleChat}
|
||||||
className={`group cursor-pointer p-2 hover:bg-gray-800 rounded-md absolute top-[1vh] left-[1vw] ${showChat ? "" : "delay-[0.75s] -translate-x-[3.3vw]"} text-[1rem] text-purple-500 flex items-center flex-nowrap z-[50] duration-[0.3s] transition-all`}
|
className={`group cursor-pointer p-2 hover:bg-gray-800 rounded-md absolute top-[1vh] left-[1vw] ${showChat ? "" : "delay-[0.75s] -translate-x-[4vw]"} text-[1rem] text-purple-500 flex items-center flex-nowrap z-[20] duration-[0.3s] transition-all`}
|
||||||
>
|
>
|
||||||
{showChat ? <ArrowRightFromLineIcon /> : <ArrowLeftFromLineIcon />}
|
{showChat ? <ArrowRightFromLineIcon /> : <ArrowLeftFromLineIcon />}
|
||||||
|
|
||||||
<small className={`absolute ${showChat ? "right-0 group-hover:-right-[4vw]" : "left-0 group-hover:-left-[4vw]"} p-1 rounded-md group-hover:bg-white/10 w-fit opacity-0 group-hover:opacity-100 text-white transition-all`}>
|
<small className={`absolute ${showChat ? justToggled ? "left-0 group-hover:-left-[4vw] group-hover:bg-white/10" : "right-0 group-hover:-right-[5vw] group-hover:bg-red-500/80" : justToggled ? "right-0 group-hover:-right-[5vw] group-hover:bg-red-500/80" : "left-0 group-hover:-left-[4vw] group-hover:bg-white/10"} p-1 rounded-md w-fit opacity-0 group-hover:opacity-100 text-white transition-all`}>
|
||||||
Press C
|
Press C
|
||||||
</small>
|
</small>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ const AllCategoriesPage: React.FC = () => {
|
|||||||
type="category"
|
type="category"
|
||||||
title="All Categories"
|
title="All Categories"
|
||||||
items={categories}
|
items={categories}
|
||||||
onClick={handleCategoryClick}
|
onItemClick={handleCategoryClick}
|
||||||
extraClasses="bg-[var(--recommend)] text-center"
|
extraClasses="bg-[var(--recommend)] text-center"
|
||||||
itemExtraClasses="w-[20vw]"
|
itemExtraClasses="w-[20vw]"
|
||||||
wrap={true}
|
wrap={true}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { SocketProvider } from "../context/SocketContext";
|
|||||||
import { useAuthModal } from "../hooks/useAuthModal";
|
import { useAuthModal } from "../hooks/useAuthModal";
|
||||||
import { useFollow } from "../hooks/useFollow";
|
import { useFollow } from "../hooks/useFollow";
|
||||||
import { useChat } from "../context/ChatContext";
|
import { useChat } from "../context/ChatContext";
|
||||||
|
import { StreamType } from "../types/StreamType";
|
||||||
|
|
||||||
// Lazy load the CheckoutForm component
|
// Lazy load the CheckoutForm component
|
||||||
const CheckoutForm = lazy(() => import("../components/Checkout/CheckoutForm"));
|
const CheckoutForm = lazy(() => import("../components/Checkout/CheckoutForm"));
|
||||||
@@ -18,17 +19,10 @@ interface VideoPageProps {
|
|||||||
streamerId: number;
|
streamerId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StreamDataProps {
|
|
||||||
streamTitle: string;
|
|
||||||
streamerName: string;
|
|
||||||
startTime: string;
|
|
||||||
categoryName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
|
const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
|
||||||
const { isLoggedIn } = useAuth();
|
const { isLoggedIn } = useAuth();
|
||||||
const { streamerName } = useParams<{ streamerName: string }>();
|
const { streamerName } = useParams<{ streamerName: string }>();
|
||||||
const [streamData, setStreamData] = useState<StreamDataProps>();
|
const [streamData, setStreamData] = useState<StreamType>();
|
||||||
const [viewerCount, setViewerCount] = useState(0);
|
const [viewerCount, setViewerCount] = useState(0);
|
||||||
const { showSideBar } = useSidebar();
|
const { showSideBar } = useSidebar();
|
||||||
const { isFollowing, checkFollowStatus, followUser, unfollowUser } =
|
const { isFollowing, checkFollowStatus, followUser, unfollowUser } =
|
||||||
@@ -66,11 +60,14 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
|
|||||||
res
|
res
|
||||||
.json()
|
.json()
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const transformedData: StreamDataProps = {
|
const transformedData: StreamType = {
|
||||||
streamerName: data.username,
|
type: "stream",
|
||||||
streamTitle: data.title,
|
id: data.stream_id,
|
||||||
|
username: data.username,
|
||||||
|
title: data.title,
|
||||||
startTime: data.start_time,
|
startTime: data.start_time,
|
||||||
categoryName: data.category_name,
|
streamCategory: data.category_name,
|
||||||
|
viewers: data.viewers,
|
||||||
};
|
};
|
||||||
setStreamData(transformedData);
|
setStreamData(transformedData);
|
||||||
|
|
||||||
@@ -134,7 +131,6 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
|
|||||||
fetch(`/api/user/subscription/${streamerName}/expiration`)
|
fetch(`/api/user/subscription/${streamerName}/expiration`)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
console.log(streamData?.streamerName, data.remaining_time);
|
|
||||||
if (data.remaining_time > 0) {
|
if (data.remaining_time > 0) {
|
||||||
setIsSubscribed(true);
|
setIsSubscribed(true);
|
||||||
}
|
}
|
||||||
@@ -183,17 +179,17 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
|
|||||||
className="text-white font-bold hover:underline mt-[0.5em]"
|
className="text-white font-bold hover:underline mt-[0.5em]"
|
||||||
onClick={() => navigate(`/user/${streamerName}`)}
|
onClick={() => navigate(`/user/${streamerName}`)}
|
||||||
>
|
>
|
||||||
{streamData ? streamData.streamerName : "Loading..."}
|
{streamerName}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stream Title */}
|
{/* Stream Title */}
|
||||||
<div className="flex flex-col items-start flex-grow">
|
<div className="flex flex-col items-start flex-grow">
|
||||||
<h2 className="text-[0.75em] lg:text-[0.85em] xl:text-[1em] font-bold">
|
<h2 className="text-[0.75em] lg:text-[0.85em] xl:text-[1em] font-bold">
|
||||||
{streamData ? streamData.streamTitle : "Loading..."}
|
{streamData ? streamData.title : "Loading..."}
|
||||||
</h2>
|
</h2>
|
||||||
<span className="text-[0.75em] lg:text-[0.85em] xl:text-[1em] text-gray-400">
|
<span className="text-[0.75em] lg:text-[0.85em] xl:text-[1em] text-gray-400">
|
||||||
{streamData ? streamData.categoryName : "Loading..."}
|
{streamData ? streamData.streamCategory : "Loading..."}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ export interface StreamType {
|
|||||||
username: string;
|
username: string;
|
||||||
streamCategory: string;
|
streamCategory: string;
|
||||||
viewers: number;
|
viewers: number;
|
||||||
|
startTime?: string;
|
||||||
thumbnail?: string;
|
thumbnail?: string;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user