From 93dfe2be64e8658839bcfe5356adf35f8cde7075 Mon Sep 17 00:00:00 2001
From: Nicolas James <Eele1Ephe7uZahRie@tutanota.com>
Date: Thu, 13 Feb 2025 18:04:18 +1100
Subject: initial commit

---
 src/web/components/nav_bar/NavBar.jsx | 174 ++++++++++++++++++++++++++++++++++
 1 file changed, 174 insertions(+)
 create mode 100644 src/web/components/nav_bar/NavBar.jsx

(limited to 'src/web/components/nav_bar/NavBar.jsx')

diff --git a/src/web/components/nav_bar/NavBar.jsx b/src/web/components/nav_bar/NavBar.jsx
new file mode 100644
index 0000000..3c22851
--- /dev/null
+++ b/src/web/components/nav_bar/NavBar.jsx
@@ -0,0 +1,174 @@
+import React, {useState, Fragment, useContext, useEffect} from "react";
+import {Link, useLocation} from "react-router-dom";
+
+import Button from "components/button/Button.jsx";
+import Login from "components/login/Login.jsx";
+import Darken from "components/darken/Darken.jsx";
+import {UserContext} from "contexts/UserContext.jsx";
+import {StateContext} from "contexts/StateContext.jsx";
+import {refreshToken, logout} from "helpers/Auth.jsx";
+import {getSubreactFromLocation, getInfoFromSubreact} from "helpers/Location.jsx";
+
+import styles from "./NavBar.css"
+import logo from "assets/images/logo.png"
+import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
+import {faUser, faPlay} from "@fortawesome/free-solid-svg-icons";
+
+function AccountInfoItem({title, onClick, path, className}) {
+    return (
+        <Link className={styles.accountInfoItem + (className ? " " + className : "")}
+            onClick={onClick}
+            to={path}>
+
+            <h3>{title}</h3>
+        </Link>
+    );
+}
+
+function AccountInfo({user, setUser}) {
+    // At this stage the user is logged in and we keep them logged in by periodically 
+    // refreshing our token.
+    useEffect(() => {
+        const interval = setInterval(() => {
+            refreshToken(user, setUser);
+        }, 58 * 60 * 1000); // refresh every 58 minutes, expires every sixty.
+        return () => clearInterval(interval);
+    }, []);
+    const [active, setActive] = useState(false);
+
+    return (
+        <div className={styles.accountContainer + (active ? " " + styles.accountContainerActive : "")} 
+            onClick={() => {setActive(!active);}}>
+            <FontAwesomeIcon icon={faUser} className={styles.accountIcon} />
+            <h2>{user.username ?? "anonymous"}</h2>
+            <FontAwesomeIcon icon={faPlay} className={styles.accountArrow + (active ? " " + styles.accountArrowActive : "")} />
+            <div className={styles.accountInfoItemList + (active ? " " + styles.accountInfoItemListActive : "")}>
+                <AccountInfoItem title="Profile" path="/settings" />
+                <AccountInfoItem title="Settings" path="/settings" />
+                <AccountInfoItem title="Logout" path="/" onClick={() => {logout(setUser);}} />
+            </div>
+        </div>
+    );
+}
+
+function LoginStatus({loginActive, setLoginActive}) {
+    const [user, setUser] = useContext(UserContext);
+
+    // Not logged in, request a login.
+    if (user == null) {
+        return (
+            <Button className={styles.loginStatus}
+                onClick={() => {setLoginActive(!loginActive);}}>
+                
+                <h2>Not Logged In</h2>
+            </Button>
+        );
+    }
+
+    return <AccountInfo user={user} setUser={setUser} />;
+}
+
+function Account() {
+    const [state, setState] = useContext(StateContext);
+    const {loginActive} = state;
+    const setLoginActive = (isActive) => {setState({...state, loginActive: isActive});};
+
+    return (
+        <Fragment>
+            <Login active={loginActive} setActive={setLoginActive} />
+            <LoginStatus loginActive={loginActive} setLoginActive={setLoginActive} />
+        </Fragment>
+    );
+}
+
+function Banner({navBarActive, setNavBarActive, shouldToggleNavBar}) {
+
+    return (
+        <div className={styles.bannerContainer}>
+            <button className={styles.burgerButton}
+                onClick={() => setNavBarActive(!navBarActive)} />
+
+            <Link to="/" 
+                onClick={shouldToggleNavBar ? () => setNavBarActive(!navBarActive) : null}>
+
+                <img className={styles.logo} src={logo} />
+                <h1>GoReact</h1>
+            </Link>
+        </div>
+    );
+}
+
+function Item({path, setNavBarActive}) {
+    const location = useLocation();
+    const subreact = path.replace("/", ""); // "a", "m" etc
+    const {icon, name} = getInfoFromSubreact(subreact);
+
+    return (
+        <Link to={path} 
+            className={styles.item + (getSubreactFromLocation(location) === subreact ? " " + styles.itemActive : "")}
+            onClick={() => setNavBarActive(false)}>
+                <FontAwesomeIcon icon={icon} className={styles.itemIcon} />
+                <h4>{name}</h4>
+        </Link>
+    );
+}
+
+function ItemList({children, title}) {
+
+    return (
+        <div className={styles.itemList}>
+            <div className={styles.titleContainer}>
+                <h3>{title}</h3>
+            </div>
+            {children && React.Children.count(children) > 0 ? children : <p>There's nothing here...</p>}
+        </div>
+    );
+}
+
+function Menu({navBarActive, setNavBarActive}) {
+
+    return (
+        <div className={styles.container}>
+            <nav className={styles.menu + (navBarActive ? " " + styles.menuActive : "")}>
+                <Banner navBarActive={navBarActive} setNavBarActive={setNavBarActive} shouldToggleNavBar />
+                <div className={styles.itemListContainer}>
+                    <ItemList title="Subreacts">
+                        <Item path="/" setNavBarActive={setNavBarActive} />
+                        <Item path="/t" setNavBarActive={setNavBarActive} />
+                        <Item path="/g" setNavBarActive={setNavBarActive} />
+                        <Item path="/k" setNavBarActive={setNavBarActive} />
+                        <Item path="/p" setNavBarActive={setNavBarActive} />
+                        <Item path="/a" setNavBarActive={setNavBarActive} />
+                        <Item path="/pr" setNavBarActive={setNavBarActive} />
+                        <Item path="/m" setNavBarActive={setNavBarActive} />
+                    </ItemList>
+
+                    {/*TODO*/}
+                    <ItemList title="Watched Threads">
+                    </ItemList>
+                    <ItemList title="Your Threads">
+                    </ItemList>
+                    <ItemList title="Recent Threads">
+                    </ItemList>
+
+                    <span>
+                        <p>GoReact 2022-2023</p>
+                    </span>
+                </div>
+            </nav>
+            <Account />
+        </div>
+    );
+}
+
+export default function NavBar() {
+    const [active, setActive] = useState(false);
+    
+    return (
+        <header className={styles.navBar}>
+            <Darken active={active} onClick={() => setActive(false)} className={styles.darken} />
+            <Banner setNavBarActive={setActive} />
+            <Menu navBarActive={active} setNavBarActive={setActive} />
+        </header>
+    );
+}
\ No newline at end of file
-- 
cgit v1.2.3

