Improved a bit more of the responsiveness and solved a bug

This commit is contained in:
Tiago Ribeiro
2023-08-28 16:25:01 +01:00
parent 3c711e0279
commit b4d856d32f
6 changed files with 113 additions and 20 deletions

View File

@@ -0,0 +1,63 @@
import clsx from "clsx";
import {IconType} from "react-icons";
import {MdSpaceDashboard} from "react-icons/md";
import {BsFileEarmarkText, BsClockHistory, BsPencil, BsGraphUp} from "react-icons/bs";
import {RiLogoutBoxFill} from "react-icons/ri";
import {SlPencil} from "react-icons/sl";
import {FaAward} from "react-icons/fa";
import Link from "next/link";
import {useRouter} from "next/router";
import axios from "axios";
import FocusLayer from "@/components/FocusLayer";
import {preventNavigation} from "@/utils/navigation.disabled";
interface Props {
path: string;
navDisabled?: boolean;
focusMode?: boolean;
onFocusLayerMouseEnter?: () => void;
className?: string;
}
interface NavProps {
Icon: IconType;
label: string;
path: string;
keyPath: string;
disabled?: boolean;
}
const Nav = ({Icon, label, path, keyPath, disabled = false}: NavProps) => (
<Link
href={!disabled ? keyPath : ""}
className={clsx(
"p-4 rounded-full flex gap-4 items-center cursor-pointer text-gray-500 hover:bg-mti-purple-light hover:text-white transition duration-300 ease-in-out",
path === keyPath && "bg-mti-purple-light text-white",
)}>
<Icon size={20} />
</Link>
);
export default function BottomBar({path, navDisabled = false, focusMode = false, onFocusLayerMouseEnter, className}: Props) {
const router = useRouter();
const logout = async () => {
axios.post("/api/logout").finally(() => {
setTimeout(() => router.reload(), 500);
});
};
const disableNavigation = preventNavigation(navDisabled, focusMode);
return (
<section className={clsx("w-full bg-white py-2 drop-shadow-2xl shadow-2xl rounded-t-2xl", className)}>
<div className="flex justify-around gap-3">
<Nav disabled={disableNavigation} Icon={MdSpaceDashboard} label="Dashboard" path={path} keyPath="/" />
<Nav disabled={disableNavigation} Icon={BsFileEarmarkText} label="Exams" path={path} keyPath="/exam" />
<Nav disabled={disableNavigation} Icon={BsPencil} label="Exercises" path={path} keyPath="/exercises" />
<Nav disabled={disableNavigation} Icon={BsGraphUp} label="Stats" path={path} keyPath="/stats" />
<Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" />
</div>
{focusMode && <FocusLayer onFocusLayerMouseEnter={onFocusLayerMouseEnter} />}
</section>
);
}

View File

@@ -1,6 +1,7 @@
import {User} from "@/interfaces/user"; import {User} from "@/interfaces/user";
import clsx from "clsx"; import clsx from "clsx";
import {useRouter} from "next/router"; import {useRouter} from "next/router";
import BottomBar from "../BottomBar";
import Navbar from "../Navbar"; import Navbar from "../Navbar";
import Sidebar from "../Sidebar"; import Sidebar from "../Sidebar";
@@ -17,13 +18,26 @@ export default function Layout({user, children, className, navDisabled = false,
const router = useRouter(); const router = useRouter();
return ( return (
<main className="w-full min-h-full h-screen flex flex-col bg-mti-gray-smoke"> <main className="w-full min-h-full h-screen flex flex-col bg-mti-gray-smoke relative">
<Navbar user={user} navDisabled={navDisabled} focusMode={focusMode} onFocusLayerMouseEnter={onFocusLayerMouseEnter} /> <Navbar user={user} navDisabled={navDisabled} focusMode={focusMode} onFocusLayerMouseEnter={onFocusLayerMouseEnter} />
<BottomBar
path={router.pathname}
navDisabled={navDisabled}
focusMode={focusMode}
onFocusLayerMouseEnter={onFocusLayerMouseEnter}
className="lg:hidden absolute bottom-0 left-0 w-full z-20"
/>
<div className="h-full w-full flex gap-2"> <div className="h-full w-full flex gap-2">
<Sidebar path={router.pathname} navDisabled={navDisabled} focusMode={focusMode} onFocusLayerMouseEnter={onFocusLayerMouseEnter} /> <Sidebar
path={router.pathname}
navDisabled={navDisabled}
focusMode={focusMode}
onFocusLayerMouseEnter={onFocusLayerMouseEnter}
className="-lg:hidden"
/>
<div <div
className={clsx( className={clsx(
"w-5/6 min-h-full h-fit mr-8 bg-white shadow-md rounded-2xl p-12 pb-8 flex flex-col gap-12 relative overflow-hidden mt-2", "w-full lg:w-5/6 min-h-full h-fit lg:mr-8 bg-white shadow-md rounded-2xl p-12 pb-8 flex flex-col gap-12 relative overflow-hidden mt-2",
className, className,
)}> )}>
{children} {children}

View File

@@ -3,6 +3,10 @@ import Link from "next/link";
import {Avatar} from "primereact/avatar"; import {Avatar} from "primereact/avatar";
import FocusLayer from "@/components/FocusLayer"; import FocusLayer from "@/components/FocusLayer";
import {preventNavigation} from "@/utils/navigation.disabled"; import {preventNavigation} from "@/utils/navigation.disabled";
import {useRouter} from "next/router";
import axios from "axios";
import {RiLogoutBoxFill} from "react-icons/ri";
import {BsPower} from "react-icons/bs";
interface Props { interface Props {
user: User; user: User;
@@ -14,18 +18,30 @@ interface Props {
/* eslint-disable @next/next/no-img-element */ /* eslint-disable @next/next/no-img-element */
export default function Navbar({user, navDisabled = false, focusMode = false, onFocusLayerMouseEnter}: Props) { export default function Navbar({user, navDisabled = false, focusMode = false, onFocusLayerMouseEnter}: Props) {
const disableNavigation = preventNavigation(navDisabled, focusMode); const disableNavigation = preventNavigation(navDisabled, focusMode);
const router = useRouter();
const logout = async () => {
axios.post("/api/logout").finally(() => {
setTimeout(() => router.reload(), 500);
});
};
return ( return (
<header className="w-full bg-transparent py-4 gap-12 flex items-center relative"> <header className="w-full bg-transparent py-4 -lg:justify-between lg:gap-12 flex items-center relative -lg:px-4">
<div className="px-8 flex gap-8 items-center"> <Link href={disableNavigation ? "" : "/"} className=" lg:px-8 flex gap-8 items-center">
<img src="/logo.png" alt="EnCoach's Logo" className="w-12" /> <img src="/logo.png" alt="EnCoach's Logo" className="w-12" />
<h1 className="font-bold text-2xl w-1/6">EnCoach</h1> <h1 className="font-bold text-2xl w-1/6 -lg:hidden">EnCoach</h1>
</div> </Link>
<div className="flex justify-between w-5/6 mr-8"> <div className="flex justify-between lg:w-5/6 lg:mr-8">
<input type="text" placeholder="Search..." className="rounded-full py-4 px-6 border border-mti-gray-platinum outline-none" /> <input
<Link href={disableNavigation ? "" : "/profile"} className="flex gap-3 items-center justify-end"> type="text"
placeholder="Search..."
className="rounded-full py-4 px-6 border border-mti-gray-platinum outline-none -lg:hidden"
/>
<Link href={disableNavigation ? "" : "/profile"} className="flex gap-6 items-center justify-end">
<img src={user.profilePicture} alt={user.name} className="w-10 h-10 rounded-full object-cover" /> <img src={user.profilePicture} alt={user.name} className="w-10 h-10 rounded-full object-cover" />
<span className="text-right">{user.name}</span> <span className="text-right -lg:hidden">{user.name}</span>
<BsPower size={40} className="bg-mti-red-light px-2 rounded-full text-white lg:hidden" />
</Link> </Link>
</div> </div>
{focusMode && <FocusLayer onFocusLayerMouseEnter={onFocusLayerMouseEnter} />} {focusMode && <FocusLayer onFocusLayerMouseEnter={onFocusLayerMouseEnter} />}

View File

@@ -15,6 +15,7 @@ interface Props {
navDisabled?: boolean; navDisabled?: boolean;
focusMode?: boolean; focusMode?: boolean;
onFocusLayerMouseEnter?: () => void; onFocusLayerMouseEnter?: () => void;
className?: string;
} }
interface NavProps { interface NavProps {
@@ -37,7 +38,7 @@ const Nav = ({Icon, label, path, keyPath, disabled = false}: NavProps) => (
</Link> </Link>
); );
export default function Sidebar({path, navDisabled = false, focusMode = false, onFocusLayerMouseEnter}: Props) { export default function Sidebar({path, navDisabled = false, focusMode = false, onFocusLayerMouseEnter, className}: Props) {
const router = useRouter(); const router = useRouter();
const logout = async () => { const logout = async () => {
@@ -49,7 +50,7 @@ export default function Sidebar({path, navDisabled = false, focusMode = false, o
const disableNavigation = preventNavigation(navDisabled, focusMode); const disableNavigation = preventNavigation(navDisabled, focusMode);
return ( return (
<section className="h-full flex bg-transparent flex-col justify-between w-1/6 px-4 py-4 pb-8 relative"> <section className={clsx("h-full flex bg-transparent flex-col justify-between w-1/6 px-4 py-4 pb-8 relative", className)}>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<Nav disabled={disableNavigation} Icon={MdSpaceDashboard} label="Dashboard" path={path} keyPath="/" /> <Nav disabled={disableNavigation} Icon={MdSpaceDashboard} label="Dashboard" path={path} keyPath="/" />
<Nav disabled={disableNavigation} Icon={BsFileEarmarkText} label="Exams" path={path} keyPath="/exam" /> <Nav disabled={disableNavigation} Icon={BsFileEarmarkText} label="Exams" path={path} keyPath="/exam" />

View File

@@ -57,13 +57,13 @@ export default function Page() {
const [sessionId, setSessionId] = useState(""); const [sessionId, setSessionId] = useState("");
const [exam, setExam] = useState<Exam>(); const [exam, setExam] = useState<Exam>();
const [isEvaluationLoading, setIsEvaluationLoading] = useState(false); const [isEvaluationLoading, setIsEvaluationLoading] = useState(false);
const [showAbandonPopup, setShowAbandonPopup] = useState(false);
const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]); const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]);
const [userSolutions, setUserSolutions] = useExamStore((state) => [state.userSolutions, state.setUserSolutions]); const [userSolutions, setUserSolutions] = useExamStore((state) => [state.userSolutions, state.setUserSolutions]);
const [showSolutions, setShowSolutions] = useExamStore((state) => [state.showSolutions, state.setShowSolutions]); const [showSolutions, setShowSolutions] = useExamStore((state) => [state.showSolutions, state.setShowSolutions]);
const [selectedModules, setSelectedModules] = useExamStore((state) => [state.selectedModules, state.setSelectedModules]); const [selectedModules, setSelectedModules] = useExamStore((state) => [state.selectedModules, state.setSelectedModules]);
const [showAbandonPopup, setShowAbandonPopup] = useState(false); const reset = useExamStore((state) => state.reset);
const setHasExamEnded = useExamStore((state) => state.setHasExamEnded);
const {user} = useUser({redirectTo: "/login"}); const {user} = useUser({redirectTo: "/login"});
@@ -330,8 +330,7 @@ export default function Page() {
abandonPopupDescription="Are you sure you want to leave the exercise? You will lose all your progress." abandonPopupDescription="Are you sure you want to leave the exercise? You will lose all your progress."
abandonConfirmButtonText="Confirm" abandonConfirmButtonText="Confirm"
onAbandon={() => { onAbandon={() => {
setExam(undefined); reset();
setSelectedModules([]);
setShowAbandonPopup(false); setShowAbandonPopup(false);
}} }}
onCancel={() => setShowAbandonPopup(false)} onCancel={() => setShowAbandonPopup(false)}

View File

@@ -60,12 +60,13 @@ export default function Page() {
const [sessionId, setSessionId] = useState(""); const [sessionId, setSessionId] = useState("");
const [exam, setExam] = useState<Exam>(); const [exam, setExam] = useState<Exam>();
const [isEvaluationLoading, setIsEvaluationLoading] = useState(false); const [isEvaluationLoading, setIsEvaluationLoading] = useState(false);
const [showAbandonPopup, setShowAbandonPopup] = useState(false);
const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]); const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]);
const [userSolutions, setUserSolutions] = useExamStore((state) => [state.userSolutions, state.setUserSolutions]); const [userSolutions, setUserSolutions] = useExamStore((state) => [state.userSolutions, state.setUserSolutions]);
const [showSolutions, setShowSolutions] = useExamStore((state) => [state.showSolutions, state.setShowSolutions]); const [showSolutions, setShowSolutions] = useExamStore((state) => [state.showSolutions, state.setShowSolutions]);
const [selectedModules, setSelectedModules] = useExamStore((state) => [state.selectedModules, state.setSelectedModules]); const [selectedModules, setSelectedModules] = useExamStore((state) => [state.selectedModules, state.setSelectedModules]);
const [showAbandonPopup, setShowAbandonPopup] = useState(false); const reset = useExamStore((state) => state.reset);
const {user} = useUser({redirectTo: "/login"}); const {user} = useUser({redirectTo: "/login"});
@@ -332,8 +333,7 @@ export default function Page() {
abandonPopupDescription="Are you sure you want to leave the exercise? You will lose all your progress." abandonPopupDescription="Are you sure you want to leave the exercise? You will lose all your progress."
abandonConfirmButtonText="Confirm" abandonConfirmButtonText="Confirm"
onAbandon={() => { onAbandon={() => {
setExam(undefined); reset();
setSelectedModules([]);
setShowAbandonPopup(false); setShowAbandonPopup(false);
}} }}
onCancel={() => setShowAbandonPopup(false)} onCancel={() => setShowAbandonPopup(false)}