Skip to content

Commit

Permalink
Merge pull request #805 from bounswe/FRONTEND-803
Browse files Browse the repository at this point in the history
feat(frontend): complete guest view
  • Loading branch information
yunusemreozdemir authored Dec 14, 2024
2 parents 92740ec + 021c041 commit b5e6cfb
Show file tree
Hide file tree
Showing 12 changed files with 409 additions and 298 deletions.
28 changes: 28 additions & 0 deletions frontend/src/components/auth/guest-auth-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useState } from "react";
import { Modal, ModalContent, ModalBody } from "@nextui-org/react";
import Login from "./login";
import Register from "./register";

export default function GuestAuthModal({ isOpen, setIsOpen }) {
const [isRegister, setIsRegister] = useState(false);

return (
<Modal
isOpen={isOpen}
onOpenChange={setIsOpen}
placement="top-center"
className="max-w-[360px] flex flex-col items-center"
backdrop="blur"
>
<ModalContent className="pb-6 gap-3">
<ModalBody className="text-center text-default-500">
{isRegister ? (
<Register setIsRegister={setIsRegister} isGuestView />
) : (
<Login setIsRegister={setIsRegister} isGuestView />
)}
</ModalBody>
</ModalContent>
</Modal>
);
}
11 changes: 8 additions & 3 deletions frontend/src/components/auth/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ type FormData = {

export default function Login({
setIsRegister,
isGuestView,
}: {
setIsRegister: (value: boolean) => void;
isGuestView?: boolean;
}) {
const [username, setUsername] = useState(Cookies.get("username") || "");
const [password, setPassword] = useState(Cookies.get("password") || "");
Expand All @@ -35,7 +37,6 @@ export default function Login({
} = useForm<FormData>();

const onSubmit = () => {

login(username, password)
.json((json) => {
Cookies.set("username", username);
Expand All @@ -45,7 +46,11 @@ export default function Login({
storeToken(json.access, "access");
storeToken(json.refresh, "refresh");

navigate("/forum");
if (isGuestView) {
navigate(0);
} else {
navigate("/forum");
}
})
.catch((err) => {
setError("root", { type: "manual", message: err.json.detail });
Expand Down Expand Up @@ -131,7 +136,7 @@ export default function Login({
<div className="text-center">
<span className="text-sm">Or continue as a </span>
<button
onClick={() => navigate("/forum")}
onClick={isGuestView ? () => navigate(0) : () => navigate("/forum")}
className="text-blue-600 hover:underline"
>
Guest
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/auth/protect-routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
if (!accessToken) {
setIsAuthenticated(false); // User is not authenticated
Cookies.remove("username");
Cookies.remove("accessToken");
Cookies.remove("refreshToken");
} else {
setIsAuthenticated(true); // User is authenticated
}
}, [navigate]);

// Show a loading state until authentication is verified
if (isAuthenticated === null) {
if (!isAuthenticated) {
navigate("/");
return <></>;
}

Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/auth/register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ type FormData = {

export default function Register({
setIsRegister,
isGuestView,
}: {
setIsRegister: (value: boolean) => void;
isGuestView?: boolean;
}) {
const [username, setUserName] = useState("");
const [email, setEmail] = useState("");
Expand Down Expand Up @@ -158,7 +160,7 @@ export default function Register({
<div className="text-center">
<span className="text-sm">Or continue as a </span>
<button
onClick={() => navigate("/forum")}
onClick={isGuestView ? () => navigate(0) : () => navigate("/forum")}
className="text-blue-600 hover:underline"
>
Guest
Expand Down
80 changes: 43 additions & 37 deletions frontend/src/components/common/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import axios from "axios";
import { BASE_URL } from "../../lib/baseURL";
import { formatTimeAgo } from "./utils";
import NotificationCard from "../notification/notification-card";
import GuestAuthModal from "../auth/guest-auth-modal";

export default function Navbar() {
const navigate = useNavigate();
Expand All @@ -34,9 +35,11 @@ export default function Navbar() {
const { logout, removeTokens, getToken } = AuthActions();

const token = getToken("access");
const isGuest = !token;
const [notifications, setNotifications] = useState([]);
const [isNotificationsViewed, setIsNotificationsViewed] = useState(false);
const [search, setSearch] = useState("");
const [guestModalOpen, setGuestModalOpen] = useState(false);

useEffect(() => {
if (!username) {
Expand Down Expand Up @@ -117,11 +120,11 @@ export default function Navbar() {
<PopoverContent>
<div className="px-2 pb-2">
<div className="text-medium font-semibold px-5 py-2 text-center">
{username || "Guest"}
{isGuest ? "Guest" : username}
</div>
<Divider className="w-full bg-zinc-300" />
<div className="flex flex-col">
{username ? (
{!isGuest ? (
<>
<Button
variant="light"
Expand Down Expand Up @@ -149,7 +152,7 @@ export default function Navbar() {
) : (
<Button
variant="light"
onClick={() => navigate("/")}
onClick={() => setGuestModalOpen(true)}
className="text-medium mt-2"
>
Login
Expand All @@ -162,6 +165,7 @@ export default function Navbar() {

return (
<div className="w-screen p-2 shadow-none" data-testid="navbar">
<GuestAuthModal isOpen={guestModalOpen} setIsOpen={setGuestModalOpen} />
<Card className="flex flex-row w-full px-5 py-3 rounded-full shadow-md">
<div className="flex-1 flex flex-row gap-6 items-center">
<Link
Expand Down Expand Up @@ -212,41 +216,43 @@ export default function Navbar() {
</div>
<div className="flex-1 flex justify-end items-center flex-row">
<ThemeSwitcher />
<Dropdown>
<DropdownTrigger>
<Button
radius="full"
isIconOnly
aria-label="more than 99 notifications"
variant="light"
onClick={() => setIsNotificationsViewed(true)}
>
{!isNotificationsViewed ? (
<Badge content="" shape="circle" color="danger" size="sm">
{!isGuest && (
<Dropdown>
<DropdownTrigger>
<Button
radius="full"
isIconOnly
aria-label="more than 99 notifications"
variant="light"
onClick={() => setIsNotificationsViewed(true)}
>
{!isNotificationsViewed ? (
<Badge content="" shape="circle" color="danger" size="sm">
<IconBell size={24} />
</Badge>
) : (
<IconBell size={24} />
</Badge>
) : (
<IconBell size={24} />
)}
</Button>
</DropdownTrigger>
<DropdownMenu
aria-label="Dropdown menu with description"
className="max-h-[360px] overflow-y-auto"
>
<DropdownSection title="Notifications" showDivider>
{notifications.map((notification) => (
<DropdownItem isReadOnly className="cursor-default">
<NotificationCard
key={notification.id}
content={notification.content}
timePassed={notification.timePassed}
/>
</DropdownItem>
))}
</DropdownSection>
</DropdownMenu>
</Dropdown>
)}
</Button>
</DropdownTrigger>
<DropdownMenu
aria-label="Dropdown menu with description"
className="max-h-[360px] overflow-y-auto"
>
<DropdownSection title="Notifications" showDivider>
{notifications.map((notification) => (
<DropdownItem isReadOnly className="cursor-default">
<NotificationCard
key={notification.id}
content={notification.content}
timePassed={notification.timePassed}
/>
</DropdownItem>
))}
</DropdownSection>
</DropdownMenu>
</Dropdown>
)}

<Popover key="bottom-end" placement="bottom-end">
<PopoverTrigger>
Expand Down
Loading

0 comments on commit b5e6cfb

Please sign in to comment.