aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPinapelz <yukais@pinapelz.com>2024-11-03 23:09:39 -0800
committerPinapelz <yukais@pinapelz.com>2024-11-03 23:09:39 -0800
commit221cb6fba838ac287860c660a4c3f94a7fe47e77 (patch)
tree68232d8978acc3ddeab92d19cba2b83ae9ca7283
parent21d496c324b025d907574076e4115919ba2e7f64 (diff)
add sidebar navigation
-rw-r--r--src/app/page.tsx74
-rw-r--r--src/components/SubscriberTable/SubscriberTable.tsx3
-rw-r--r--src/components/TitleBar/TitleBar.tsx245
3 files changed, 245 insertions, 77 deletions
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 9c243db..1723043 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,46 +1,50 @@
import SubscriberTable, {
- type SubscriberDataTableProp,
+ type SubscriberDataTableProp,
} from "../components/SubscriberTable/SubscriberTable";
import TitleBar from "../components/TitleBar/TitleBar";
async function Home() {
- const graphURL = process.env.NEXT_PUBLIC_GRAPH_URL;
- const data: SubscriberDataTableProp = await getData();
- return (
- <>
- <TitleBar title="PhaseTracker" backgroundColor="black" />
- <div
- className="sm:block hidden mt-4"
- style={{ overflow: "hidden", height: "105vh", position: "relative" }}
- >
- <iframe
- title="Phase Connect Subscriber Count Graph"
- src={graphURL}
- style={{ position: "absolute", top: 0, left: 0 }}
- width="100%"
- height="100%"
- />
- </div>
- <SubscriberTable {...data} />
- </>
- );
+ const graphURL = process.env.NEXT_PUBLIC_GRAPH_URL;
+ const data: SubscriberDataTableProp = await getData();
+ return (
+ <>
+ <TitleBar title="PhaseTracker" backgroundColor="black" />
+ <div
+ className="sm:block hidden mt-4"
+ style={{
+ overflow: "hidden",
+ height: "105vh",
+ position: "relative",
+ }}
+ >
+ <iframe
+ title="Phase Connect Subscriber Count Graph"
+ src={graphURL}
+ style={{ position: "absolute", top: 0, left: 0 }}
+ width="100%"
+ height="100%"
+ />
+ </div>
+ <SubscriberTable {...data} />
+ </>
+ );
}
async function getData() {
- const apiUrl = process.env.NEXT_PUBLIC_API_URL_TESTING;
- const endpoint = "/api/subscribers";
- const headers = {
- "Cache-Control": "no-cache",
- };
- const cacheOption = "no-cache";
+ const apiUrl = process.env.NEXT_PUBLIC_API_URL_TESTING;
+ const endpoint = "/api/subscribers";
+ const headers = {
+ "Cache-Control": "no-cache",
+ };
+ const cacheOption = "no-cache";
- const response = await fetch(`${apiUrl}${endpoint}`, {
- headers: headers,
- cache: cacheOption,
- });
- if (!response.ok) {
- console.log(response.statusText);
- }
- return response.json();
+ const response = await fetch(`${apiUrl}${endpoint}`, {
+ headers: headers,
+ cache: cacheOption,
+ });
+ if (!response.ok) {
+ console.log(response.statusText);
+ }
+ return response.json();
}
export default Home;
diff --git a/src/components/SubscriberTable/SubscriberTable.tsx b/src/components/SubscriberTable/SubscriberTable.tsx
index 43c8c16..766cd3d 100644
--- a/src/components/SubscriberTable/SubscriberTable.tsx
+++ b/src/components/SubscriberTable/SubscriberTable.tsx
@@ -30,9 +30,6 @@ const DataTable = ({ channel_data, timestamp }: SubscriberDataTableProp) => {
<h1 className="text-2xl font-bold text-gray-800">
Subscriber Count
</h1>
- <h2 className="text-xl text-gray-800">
- Click on a row to view more details!
- </h2>
<p className="text-gray-500 text-sm">
Updated Hourly. Retrieved at: {timestamp}
</p>
diff --git a/src/components/TitleBar/TitleBar.tsx b/src/components/TitleBar/TitleBar.tsx
index 127534e..c4a65c4 100644
--- a/src/components/TitleBar/TitleBar.tsx
+++ b/src/components/TitleBar/TitleBar.tsx
@@ -1,51 +1,218 @@
+"use client";
import type React from "react";
import "../TitleBar/TitleBarStyle.css";
-import { faHouse } from "@fortawesome/free-solid-svg-icons";
+import {
+ faHouse,
+ faBars,
+ faTimes,
+ faChevronDown,
+ faChevronUp,
+ faSpinner,
+} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { useState, useEffect } from "react";
+import Link from "next/link";
interface TitleBarProps {
- title: string;
- redirectUrl?: string;
- showHomeButton?: boolean;
- backgroundColor?: string;
+ title: string;
+ redirectUrl?: string;
+ showHomeButton?: boolean;
+ backgroundColor?: string;
}
const TitleBar: React.FC<TitleBarProps> = ({
- title,
- redirectUrl,
- showHomeButton,
- backgroundColor,
+ title,
+ redirectUrl,
+ showHomeButton,
+ backgroundColor,
}) => {
- return (
- <>
- <div
- className="title-bar p-5 shadow-md"
- style={{ backgroundColor: backgroundColor || "#2D4B71" }}
- >
- <div
- style={{
- display: "flex",
- justifyContent: "space-between",
- alignItems: "center",
- }}
- >
- <a href={redirectUrl}>
- <span
- className="text-white text-4xl font-bold"
- style={{ fontFamily: "Quantico, sans-serif" }}
- >
- {title}
- </span>
- </a>
- {showHomeButton && (
- <a href="/" className="text-white text-3xl">
- <FontAwesomeIcon icon={faHouse} />
- </a>
- )}
- </div>
- </div>
- </>
- );
+ const hideFromSidebar = ["Fuura Yuri"]; // List of names to hide (e.g., due to graduation)
+ const [isSidebarOpen, setIsSidebarOpen] = useState(false);
+ const [isMounted, setIsMounted] = useState(false);
+ const [groupingData, setPhaseData] = useState<{
+ [key: string]: string[];
+ } | null>(null);
+ const [collapsedSections, setCollapsedSections] = useState<{
+ [key: string]: boolean;
+ }>({});
+ const [loadingMember, setLoadingMember] = useState<string | null>(null);
+
+ useEffect(() => {
+ setIsMounted(true);
+ const fetchPhaseData = async () => {
+ const apiUrl = process.env.NEXT_PUBLIC_API_URL_TESTING;
+ try {
+ const response = await fetch(apiUrl + "/api/groups");
+ const data = await response.json();
+ setPhaseData(data);
+ const initialCollapsedState = Object.keys(data).reduce(
+ (acc, phase) => {
+ acc[phase] = true;
+ return acc;
+ },
+ {} as { [key: string]: boolean },
+ );
+ setCollapsedSections(initialCollapsedState);
+ } catch (error) {
+ console.error("Error fetching phase data:", error);
+ }
+ };
+
+ fetchPhaseData();
+ }, []);
+
+ const toggleSidebar = () => {
+ setIsSidebarOpen(!isSidebarOpen);
+ };
+
+ const toggleSection = (phase: string) => {
+ setCollapsedSections((prevState) => ({
+ ...prevState,
+ [phase]: !prevState[phase],
+ }));
+ };
+
+ const handleMemberClick = (member: string) => {
+ setLoadingMember(member);
+ };
+
+ if (!isMounted) {
+ return null;
+ }
+
+ return (
+ <>
+ <div
+ className="title-bar p-5 shadow-md"
+ style={{ backgroundColor: backgroundColor || "#2D4B71" }}
+ >
+ <div
+ style={{
+ display: "flex",
+ justifyContent: "space-between",
+ alignItems: "center",
+ }}
+ >
+ <button
+ onClick={toggleSidebar}
+ className="text-white text-3xl mr-4 focus:outline-none"
+ >
+ <FontAwesomeIcon
+ icon={isSidebarOpen ? faTimes : faBars}
+ />
+ </button>
+ <a href={redirectUrl}>
+ <span
+ className="text-white text-4xl font-bold"
+ style={{ fontFamily: "Quantico, sans-serif" }}
+ >
+ {title}
+ </span>
+ </a>
+ {showHomeButton && (
+ <a href="/" className="ml-2 text-white text-3xl">
+ <FontAwesomeIcon icon={faHouse} />
+ </a>
+ )}
+ </div>
+ </div>
+
+ {/* Sidebar */}
+ <div
+ className={`fixed top-0 left-0 h-screen bg-black text-white shadow-lg transition-transform transform ${
+ isSidebarOpen ? "translate-x-0" : "-translate-x-full"
+ } duration-500 ease-in-out z-50`}
+ style={{ width: "16rem", fontFamily: "Quantico, sans-serif" }}
+ >
+ <div className="p-4 text-3xl font-bold border-b border-gray-700">
+ PhaseTracker
+ </div>
+ <ul className="text-xl border-b border-gray-700">
+ <Link href="/">
+ <li className="p-4 hover:bg-gray-700 transition-colors duration-300">
+ Home
+ </li>
+ </Link>
+ <Link href="/about">
+ <li className="p-4 hover:bg-gray-700 transition-colors duration-300">
+ About
+ </li>
+ </Link>
+ </ul>
+
+ <ul className="mt-4 text-xl">
+ {groupingData ? (
+ Object.entries(groupingData).map(([group, members]) => (
+ <li key={group} className="p-4">
+ <div
+ className="flex justify-between items-center cursor-pointer select-none"
+ onClick={() => toggleSection(group)}
+ >
+ <span className="font-bold text-lg">
+ {group}
+ </span>
+ <FontAwesomeIcon
+ icon={
+ collapsedSections[group]
+ ? faChevronDown
+ : faChevronUp
+ }
+ />
+ </div>
+ {!collapsedSections[group] && (
+ <ul className="ml-4 mt-2">
+ {members
+ .filter(
+ (member) =>
+ !hideFromSidebar.includes(
+ member,
+ ),
+ )
+ .map((member) => (
+ <a
+ href={`/stats/${member}`}
+ key={member}
+ >
+ <li
+ className="p-1 hover:bg-gray-700 transition-colors duration-300 flex items-center"
+ onClick={() =>
+ handleMemberClick(
+ member,
+ )
+ }
+ >
+ {member}
+ {loadingMember ===
+ member && (
+ <FontAwesomeIcon
+ icon={faSpinner}
+ spin
+ className="ml-2"
+ />
+ )}
+ </li>
+ </a>
+ ))}
+ </ul>
+ )}
+ </li>
+ ))
+ ) : (
+ <li className="p-4">Loading...</li>
+ )}
+ </ul>
+ </div>
+
+ {/* Content overlay when sidebar is open */}
+ {isSidebarOpen && (
+ <div
+ className="fixed top-0 left-0 w-full h-full bg-black opacity-50 transition-opacity duration-500"
+ style={{ zIndex: 40 }}
+ onClick={toggleSidebar}
+ ></div>
+ )}
+ </>
+ );
};
export default TitleBar;
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage