Skip to content

Commit 05de1cc

Browse files
dylanwzahnafloljoanna209
authored
feat(frontend)/ELEC-499: implement navbar (#225)
* add initial oauth support * Moved navbar to layout * Added links to icons * feature/ELEC-499: added responsiveness * feature/ELEC-499: interactive logout button * feature/ELEC-499: collapsed navbar * feature/ELEC-499: re-factored into collapsed and non-collapsed views * feature/ELEC-499: tooltips * feature/ELEC-499: xs responsiveness * feature/ELEC-499: changed link to a * feature/ELEC-499: fixed linting * add federated authentication support * add federated authentication support * feature/ELEC-499: restored package-lock.json * add comment for module augmentation * create middleware * feature/ELEC-499: re-structure logic * add initial oauth support * remove auth server remove login window remove validation on course page * remove auth server modify docker * feature/ELEC-499: transition * feature/ELEC-499: dark background + auth * remove dull background * fix user typing --------- Co-authored-by: Ahnaf Tazwar <ahnaftazwar368@gmail.com> Co-authored-by: joanna209 <80564580+joanna209@users.noreply.github.com>
1 parent d9b2871 commit 05de1cc

File tree

5 files changed

+828
-144
lines changed

5 files changed

+828
-144
lines changed
Lines changed: 6 additions & 0 deletions
Loading

frontend-v2/src/app/layout.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import "./globals.css";
2+
import Navbar from "@/components/Navbar/Navbar";
3+
import { getServerSession } from "next-auth";
4+
import { authOptions } from "@/lib/auth";
25

36
export const metadata = {
47
title: "uni-lectives",
58
description: "Course review website for UNSW made by CSESoc",
69
};
710

8-
export default function RootLayout({
11+
export default async function RootLayout({
912
children,
1013
}: {
1114
children: React.ReactNode;
1215
}) {
16+
const session = await getServerSession(authOptions);
17+
console.log("layout re-rendered")
1318
return (
1419
<html lang="en" className="font-custom">
15-
<body>{children}</body>
20+
<body>
21+
<Navbar zid={session?.user?.id}/>
22+
<div className="ml-20 xs:ml-15">{children}</div>
23+
</body>
1624
</html>
1725
);
1826
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
"use client";
2+
3+
import { useState, useRef, useEffect } from "react";
4+
import Image from "next/image";
5+
import logo from "../../../public/uni-lectives.svg";
6+
import { BookOpenIcon, PencilSquareIcon, ShieldCheckIcon, UserCircleIcon, BarsArrowDownIcon, BarsArrowUpIcon, MoonIcon, ArrowRightOnRectangleIcon, ArrowLeftOnRectangleIcon } from "@heroicons/react/24/outline";
7+
import Tooltip from "@/components/Tooltip/Tooltip";
8+
9+
type NavbarProps = {
10+
zid: string | undefined;
11+
}
12+
13+
export default function Navbar({
14+
zid
15+
}: NavbarProps ) {
16+
const [logout, setLogout] = useState(false);
17+
const [collapsed, setCollapsed] = useState(true);
18+
19+
const ref = useRef<HTMLDivElement>(null);
20+
21+
useEffect(() => {
22+
function handleClickOutside(event: any) {
23+
if (ref.current && !ref.current.contains(event.target)) {
24+
setCollapsed(true);
25+
}
26+
}
27+
// Bind the event listener
28+
document.addEventListener("mousedown", handleClickOutside);
29+
return () => {
30+
// Unbind the event listener on clean up
31+
document.removeEventListener("mousedown", handleClickOutside);
32+
};
33+
}, [ref]);
34+
35+
function handleLogout(e: React.MouseEvent<Element, MouseEvent>) {
36+
setLogout(true);
37+
if (!logout) {
38+
e.preventDefault();
39+
}
40+
}
41+
42+
function handleCollapse(val: boolean) {
43+
setCollapsed(val);
44+
}
45+
46+
return (
47+
// Enlarged (non-collapsed) View
48+
<div ref={ref} className={collapsed ? "fixed flex flex-col items-center w-20 h-screen gap-4 p-4 duration-150 bg-gray-50 z-50 xs:p-2 xs:w-15 xs:gap-2" : "fixed flex flex-col w-72 h-screen gap-4 p-4 bg-gray-50 z-40 duration-150"}>
49+
{/* Logo */}
50+
<div className="flex flex-row items-center justify-between h-10 p-2">
51+
<Tooltip tooltip={collapsed ? "" : ""}>
52+
<a href="/">
53+
<Image
54+
src={logo}
55+
width={33}
56+
height={33}
57+
alt="logo"
58+
priority
59+
/>
60+
</a>
61+
</Tooltip>
62+
<p className={collapsed ? "hidden" : "text-xl font-semibold whitespace-nowrap "}>uni-lectives</p>
63+
<BarsArrowDownIcon onClick={() => handleCollapse(true)} className={collapsed ? "hidden" : "w-12 h-12 p-3 rotate-90 hover:bg-slate-200 rounded-xl"} />
64+
</div>
65+
{/* Navbar Container */}
66+
<div className="flex flex-col h-full w-full justify-between border-t-2 border-gray-200">
67+
{/* Review Options */}
68+
<div className={`flex flex-col gap-3 py-3 ${collapsed ? "items-center" : "items-left"}`}>
69+
<a className={collapsed ? "flex" : "flex flex-row items-center hover:bg-slate-200 rounded-xl"} href="/">
70+
<Tooltip tooltip={collapsed ? "Browse Courses" : ""}>
71+
<BookOpenIcon className="w-12 h-12 p-3 hover:bg-slate-200 rounded-xl" />
72+
</Tooltip>
73+
<span className={collapsed ? "hidden" : "whitespace-nowrap"}>Browse Courses</span>
74+
</a>
75+
<a className={collapsed ? "flex" : "flex flex-row items-center hover:bg-slate-200 rounded-xl"} href="/user/zid">
76+
<Tooltip tooltip={collapsed ? "My Reviews" : ""}>
77+
<PencilSquareIcon className="w-12 h-12 p-3 hover:bg-slate-200 rounded-xl" />
78+
</Tooltip>
79+
<span className={collapsed ? "hidden" : "whitespace-nowrap"}>My Reviews</span>
80+
</a>
81+
<a className={collapsed ? "flex" : "flex flex-row items-center hover:bg-slate-200 rounded-xl"} href="/terms-and-conditions">
82+
<Tooltip tooltip={collapsed ? "Terms and Conditions" : ""}>
83+
<ShieldCheckIcon className="w-12 h-12 p-3 hover:bg-slate-200 rounded-xl" />
84+
</Tooltip>
85+
<span className={collapsed ? "hidden" : "whitespace-nowrap"}>Terms and Conditions</span>
86+
</a>
87+
</div>
88+
{/* Account Options */}
89+
<div className={`flex flex-col gap-4 py-2 ${collapsed ? "items-center" : "items-left"}`}>
90+
<div className={collapsed ? "flex flex-col gap-3" : "flex flex-row justify-between gap-2"}>
91+
<Tooltip tooltip={"Expand"}>
92+
<BarsArrowUpIcon onClick={(e) => setCollapsed(false)} className={collapsed ? "w-12 h-12 p-3 rotate-90 hover:bg-slate-200 rounded-xl" : "hidden"} />
93+
</Tooltip>
94+
{collapsed ? (
95+
<Tooltip tooltip={zid ? `${zid}` : "My Account"}>
96+
<a href="user/zid">
97+
<UserCircleIcon className="w-12 h-12 p-3 hover:bg-slate-200 rounded-xl" />
98+
</a>
99+
</Tooltip>
100+
) : (
101+
<a className="flex flex-row w-full items-center hover:bg-slate-200 rounded-xl" href={zid ? `user/${zid}` : "api/auth/signin"}>
102+
<UserCircleIcon className="w-12 h-12 p-3" />
103+
<span className="whitespace-nowrap">{zid ? zid : "My Account"}</span>
104+
</a>
105+
)}
106+
{collapsed ? (
107+
<Tooltip tooltip={"Dark Mode"}>
108+
<MoonIcon title="Dark Mode" className="w-12 h-12 p-3 hover:bg-slate-200 rounded-xl" />
109+
</Tooltip>
110+
) : (
111+
<MoonIcon title="Dark Mode" className="w-12 h-12 p-3 hover:bg-slate-200 rounded-xl" />
112+
)}
113+
</div>
114+
{zid ? (
115+
collapsed ? (
116+
<Tooltip tooltip={logout ? "Are you sure?" : "Logout"}>
117+
<a
118+
href={logout ? "/api/auth/signout" : "#"}
119+
onClick={(e) => { setLogout(true); if (!logout) { e.preventDefault() } }}
120+
onMouseLeave={() => setLogout(false)}
121+
className={`flex flex-row items-center justify-center rounded-xl gap-2 ${logout ? "hover:text-red-600 hover:bg-red-100" : "hover:bg-slate-200"}`}>
122+
<ArrowRightOnRectangleIcon className="w-12 h-12 p-3" />
123+
</a>
124+
</Tooltip>
125+
) : (
126+
<a
127+
href={logout ? "/api/auth/signout" : "#"}
128+
onClick={(e) => handleLogout(e)}
129+
onMouseLeave={() => setLogout(false)}
130+
className={`flex flex-row items-center justify-center rounded-xl gap-2 ${logout ? "hover:text-red-600 hover:bg-red-100" : "hover:bg-slate-200"}`}>
131+
<ArrowRightOnRectangleIcon className="w-6 h-12 py-3" />
132+
{!logout ? (
133+
<span className="whitespace-nowrap">Logout</span>
134+
) : (
135+
<span>Are you sure?</span>
136+
)}
137+
</a>
138+
)) : (
139+
collapsed ? (
140+
<Tooltip tooltip={"Login"}>
141+
<a
142+
href={"/api/auth/signin"}
143+
className="flex flex-row items-center justify-center rounded-xl gap-2 hover:bg-slate-200">
144+
<ArrowLeftOnRectangleIcon className="w-12 h-12 rotate-180 p-3" />
145+
</a>
146+
</Tooltip>
147+
) : (
148+
<a
149+
href={"/api/auth/signin"}
150+
className="flex flex-row items-center justify-center rounded-xl gap-2 hover:bg-slate-200">
151+
<ArrowLeftOnRectangleIcon className="w-6 h-12 rotate-180 py-3" />
152+
<span>Login</span>
153+
</a>
154+
))}
155+
156+
<div className="flex flex-col gap-3 max-h-20">
157+
<span className={collapsed ? "hidden" : "text-xs"}>By using this site, you agree to the <a href="/terms-and-conditions" className="inline text-blue-500 hover:underline">terms and conditions</a>.</span>
158+
<span className={collapsed ? "hidden" : "text-xs"}>© CSESoc 2023, v1.0.0</span>
159+
</div>
160+
</div>
161+
</div>
162+
</div>
163+
)
164+
165+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { ReactNode } from "react";
2+
3+
type TooltipProps = {
4+
children: ReactNode;
5+
tooltip?: string;
6+
};
7+
8+
export default function Tooltip({ children, tooltip }: TooltipProps) {
9+
return (
10+
<div className="group relative inline-block">
11+
{children}
12+
{tooltip && (
13+
<div className="
14+
scale-0 group-hover:scale-100
15+
absolute left-full top-1/2 transform -translate-y-1/2 ml-1
16+
whitespace-nowrap"
17+
>
18+
<div className="relative">
19+
<div className="
20+
absolute right-full top-1/2 transform -translate-y-1/2
21+
w-0 h-0 border-t-4 border-t-transparent border-r-8 border-b-4 border-b-transparent border-r-white"
22+
/>
23+
<span className="py-2 px-4 text-sm text-black whitespace-nowrap rounded-md bg-white shadow-lg">
24+
{tooltip}
25+
</span>
26+
</div>
27+
</div>
28+
)}
29+
</div>
30+
);
31+
}

0 commit comments

Comments
 (0)