ENCOA-316 ENCOA-317:
Refactor components to remove Layout wrapper and pass it in the App component , implemented a skeleton feedback while loading page and improved API calls related to Dashboard/User Profile
This commit is contained in:
@@ -2,17 +2,16 @@ import clsx from "clsx";
|
||||
import { IconType } from "react-icons";
|
||||
import { MdSpaceDashboard } from "react-icons/md";
|
||||
import {
|
||||
BsFileEarmarkText,
|
||||
BsClockHistory,
|
||||
BsPencil,
|
||||
BsGraphUp,
|
||||
BsChevronBarRight,
|
||||
BsChevronBarLeft,
|
||||
BsShieldFill,
|
||||
BsCloudFill,
|
||||
BsCurrencyDollar,
|
||||
BsClipboardData,
|
||||
BsPeople,
|
||||
BsFileEarmarkText,
|
||||
BsClockHistory,
|
||||
BsGraphUp,
|
||||
BsChevronBarRight,
|
||||
BsChevronBarLeft,
|
||||
BsShieldFill,
|
||||
BsCloudFill,
|
||||
BsCurrencyDollar,
|
||||
BsClipboardData,
|
||||
BsPeople,
|
||||
} from "react-icons/bs";
|
||||
import { CiDumbbell } from "react-icons/ci";
|
||||
import { RiLogoutBoxFill } from "react-icons/ri";
|
||||
@@ -24,218 +23,454 @@ import { preventNavigation } from "@/utils/navigation.disabled";
|
||||
import usePreferencesStore from "@/stores/preferencesStore";
|
||||
import { User } from "@/interfaces/user";
|
||||
import useTicketsListener from "@/hooks/useTicketsListener";
|
||||
import { checkAccess, getTypesOfUser } from "@/utils/permissions";
|
||||
import { getTypesOfUser } from "@/utils/permissions";
|
||||
import usePermissions from "@/hooks/usePermissions";
|
||||
import { EntityWithRoles } from "@/interfaces/entity";
|
||||
import { useAllowedEntities, useAllowedEntitiesSomePermissions } from "@/hooks/useEntityPermissions";
|
||||
import {
|
||||
useAllowedEntities,
|
||||
useAllowedEntitiesSomePermissions,
|
||||
} from "@/hooks/useEntityPermissions";
|
||||
import { useMemo } from "react";
|
||||
import { PermissionType } from "../interfaces/permissions";
|
||||
|
||||
interface Props {
|
||||
path: string;
|
||||
navDisabled?: boolean;
|
||||
focusMode?: boolean;
|
||||
onFocusLayerMouseEnter?: () => void;
|
||||
className?: string;
|
||||
user: User;
|
||||
entities?: EntityWithRoles[]
|
||||
path: string;
|
||||
navDisabled?: boolean;
|
||||
focusMode?: boolean;
|
||||
onFocusLayerMouseEnter?: () => void;
|
||||
className?: string;
|
||||
user: User;
|
||||
entities?: EntityWithRoles[];
|
||||
}
|
||||
|
||||
interface NavProps {
|
||||
Icon: IconType;
|
||||
label: string;
|
||||
path: string;
|
||||
keyPath: string;
|
||||
disabled?: boolean;
|
||||
isMinimized?: boolean;
|
||||
badge?: number;
|
||||
Icon: IconType;
|
||||
label: string;
|
||||
path: string;
|
||||
keyPath: string;
|
||||
disabled?: boolean;
|
||||
isMinimized?: boolean;
|
||||
badge?: number;
|
||||
}
|
||||
|
||||
const Nav = ({ Icon, label, path, keyPath, disabled = false, isMinimized = false, badge }: NavProps) => {
|
||||
return (
|
||||
<Link
|
||||
href={!disabled ? keyPath : ""}
|
||||
className={clsx(
|
||||
"flex items-center gap-4 rounded-full p-4 text-gray-500 hover:text-white",
|
||||
"transition-all duration-300 ease-in-out relative",
|
||||
disabled ? "hover:bg-mti-gray-dim cursor-not-allowed" : "hover:bg-mti-purple-light cursor-pointer",
|
||||
path.startsWith(keyPath) && "bg-mti-purple-light text-white",
|
||||
isMinimized ? "w-fit" : "w-full min-w-[200px] px-8 2xl:min-w-[220px]",
|
||||
)}>
|
||||
<Icon size={24} />
|
||||
{!isMinimized && <span className="text-lg font-semibold">{label}</span>}
|
||||
{!!badge && badge > 0 && (
|
||||
<div
|
||||
className={clsx(
|
||||
"bg-mti-purple-light h-5 w-5 text-xs rounded-full flex items-center justify-center text-white",
|
||||
"transition ease-in-out duration-300",
|
||||
isMinimized && "absolute right-0 top-0",
|
||||
)}>
|
||||
{badge}
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
const Nav = ({
|
||||
Icon,
|
||||
label,
|
||||
path,
|
||||
keyPath,
|
||||
disabled = false,
|
||||
isMinimized = false,
|
||||
badge,
|
||||
}: NavProps) => {
|
||||
return (
|
||||
<Link
|
||||
href={!disabled ? keyPath : ""}
|
||||
className={clsx(
|
||||
"flex items-center gap-4 rounded-full p-4 text-gray-500 hover:text-white",
|
||||
"transition-all duration-300 ease-in-out relative",
|
||||
disabled
|
||||
? "hover:bg-mti-gray-dim cursor-not-allowed"
|
||||
: "hover:bg-mti-purple-light cursor-pointer",
|
||||
path.startsWith(keyPath) && "bg-mti-purple-light text-white",
|
||||
isMinimized ? "w-fit" : "w-full min-w-[200px] px-8 2xl:min-w-[220px]"
|
||||
)}
|
||||
>
|
||||
<Icon size={24} />
|
||||
{!isMinimized && <span className="text-lg font-semibold">{label}</span>}
|
||||
{!!badge && badge > 0 && (
|
||||
<div
|
||||
className={clsx(
|
||||
"bg-mti-purple-light h-5 w-5 text-xs rounded-full flex items-center justify-center text-white",
|
||||
"transition ease-in-out duration-300",
|
||||
isMinimized && "absolute right-0 top-0"
|
||||
)}
|
||||
>
|
||||
{badge}
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default function Sidebar({
|
||||
path,
|
||||
entities = [],
|
||||
navDisabled = false,
|
||||
focusMode = false,
|
||||
user,
|
||||
onFocusLayerMouseEnter,
|
||||
className
|
||||
path,
|
||||
entities = [],
|
||||
navDisabled = false,
|
||||
focusMode = false,
|
||||
user,
|
||||
onFocusLayerMouseEnter,
|
||||
className,
|
||||
}: Props) {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const isAdmin = useMemo(() => ['developer', 'admin'].includes(user?.type), [user?.type])
|
||||
const isAdmin = useMemo(
|
||||
() => ["developer", "admin"].includes(user?.type),
|
||||
[user?.type]
|
||||
);
|
||||
|
||||
const [isMinimized, toggleMinimize] = usePreferencesStore((state) => [state.isSidebarMinimized, state.toggleSidebarMinimized]);
|
||||
const [isMinimized, toggleMinimize] = usePreferencesStore((state) => [
|
||||
state.isSidebarMinimized,
|
||||
state.toggleSidebarMinimized,
|
||||
]);
|
||||
|
||||
const { totalAssignedTickets } = useTicketsListener(user.id);
|
||||
const { permissions } = usePermissions(user.id);
|
||||
const { permissions } = usePermissions(user.id);
|
||||
|
||||
const entitiesAllowStatistics = useAllowedEntities(user, entities, "view_statistics")
|
||||
const entitiesAllowPaymentRecord = useAllowedEntities(user, entities, "view_payment_record")
|
||||
const entitiesAllowStatistics = useAllowedEntities(
|
||||
user,
|
||||
entities,
|
||||
"view_statistics"
|
||||
);
|
||||
const entitiesAllowPaymentRecord = useAllowedEntities(
|
||||
user,
|
||||
entities,
|
||||
"view_payment_record"
|
||||
);
|
||||
|
||||
const entitiesAllowGeneration = useAllowedEntitiesSomePermissions(user, entities, [
|
||||
"generate_reading", "generate_listening", "generate_writing", "generate_speaking", "generate_level"
|
||||
])
|
||||
const entitiesAllowGeneration = useAllowedEntitiesSomePermissions(
|
||||
user,
|
||||
entities,
|
||||
[
|
||||
"generate_reading",
|
||||
"generate_listening",
|
||||
"generate_writing",
|
||||
"generate_speaking",
|
||||
"generate_level",
|
||||
]
|
||||
);
|
||||
|
||||
const logout = async () => {
|
||||
axios.post("/api/logout").finally(() => {
|
||||
setTimeout(() => router.reload(), 500);
|
||||
});
|
||||
};
|
||||
const sidebarPermissions = useMemo<{ [key: string]: boolean }>(() => {
|
||||
if (user.type === "developer") {
|
||||
return {
|
||||
viewExams: true,
|
||||
viewStats: true,
|
||||
viewRecords: true,
|
||||
viewTickets: true,
|
||||
viewClassrooms: true,
|
||||
viewSettings: true,
|
||||
viewPaymentRecord: true,
|
||||
viewGeneration: true,
|
||||
};
|
||||
}
|
||||
const sidebarPermissions: { [key: string]: boolean } = {
|
||||
viewExams: false,
|
||||
viewStats: false,
|
||||
viewRecords: false,
|
||||
viewTickets: false,
|
||||
viewClassrooms: false,
|
||||
viewSettings: false,
|
||||
viewPaymentRecord: false,
|
||||
viewGeneration: false,
|
||||
};
|
||||
|
||||
const disableNavigation = preventNavigation(navDisabled, focusMode);
|
||||
if (!user || !user?.type) return sidebarPermissions;
|
||||
|
||||
return (
|
||||
<section
|
||||
className={clsx(
|
||||
"relative flex h-full flex-col justify-between bg-transparent px-4 py-4 pb-8",
|
||||
isMinimized ? "w-fit" : "-xl:w-fit w-1/6",
|
||||
className,
|
||||
)}>
|
||||
<div className="-xl:hidden flex-col gap-3 xl:flex">
|
||||
<Nav disabled={disableNavigation} Icon={MdSpaceDashboard} label="Dashboard" path={path} keyPath="/dashboard" isMinimized={isMinimized} />
|
||||
{checkAccess(user, ["student", "teacher", "developer"], permissions, "viewExams") && (
|
||||
<Nav disabled={disableNavigation} Icon={BsFileEarmarkText} label="Practice" path={path} keyPath="/exam" isMinimized={isMinimized} />
|
||||
)}
|
||||
{checkAccess(user, getTypesOfUser(["agent"])) && entitiesAllowStatistics.length > 0 && (
|
||||
<Nav disabled={disableNavigation} Icon={BsGraphUp} label="Stats" path={path} keyPath="/stats" isMinimized={isMinimized} />
|
||||
)}
|
||||
{checkAccess(user, ["developer", "admin", "mastercorporate", "corporate", "teacher", "student"], permissions) && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsPeople}
|
||||
label="Classrooms"
|
||||
path={path}
|
||||
keyPath="/classrooms"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{checkAccess(user, getTypesOfUser(["agent"]), permissions, "viewRecords") && (
|
||||
<Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" isMinimized={isMinimized} />
|
||||
)}
|
||||
{checkAccess(user, getTypesOfUser(["agent"]), permissions, "viewRecords") && (
|
||||
<Nav disabled={disableNavigation} Icon={CiDumbbell} label="Training" path={path} keyPath="/training" isMinimized={isMinimized} />
|
||||
)}
|
||||
{checkAccess(user, ["admin", "developer", "agent", "corporate", "mastercorporate"]) && entitiesAllowPaymentRecord.length > 0 && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsCurrencyDollar}
|
||||
label="Payment Record"
|
||||
path={path}
|
||||
keyPath="/payment-record"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{checkAccess(user, ["admin", "developer", "corporate", "teacher", "mastercorporate"]) && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsShieldFill}
|
||||
label="Settings"
|
||||
path={path}
|
||||
keyPath="/settings"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{checkAccess(user, ["admin", "developer", "agent"], permissions, "viewTickets") && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsClipboardData}
|
||||
label="Tickets"
|
||||
path={path}
|
||||
keyPath="/tickets"
|
||||
isMinimized={isMinimized}
|
||||
badge={totalAssignedTickets}
|
||||
/>
|
||||
)}
|
||||
{checkAccess(user, ["admin", "developer", "teacher", 'corporate', 'mastercorporate'])
|
||||
&& (entitiesAllowGeneration.length > 0 || isAdmin) && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsCloudFill}
|
||||
label="Generation"
|
||||
path={path}
|
||||
keyPath="/generation"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="-xl:flex flex-col gap-3 xl:hidden">
|
||||
<Nav disabled={disableNavigation} Icon={MdSpaceDashboard} label="Dashboard" path={path} keyPath="/" isMinimized />
|
||||
<Nav disabled={disableNavigation} Icon={BsFileEarmarkText} label="Exams" path={path} keyPath="/exam" isMinimized />
|
||||
{checkAccess(user, getTypesOfUser(["agent"]), permissions, "viewStats") && (
|
||||
<Nav disabled={disableNavigation} Icon={BsGraphUp} label="Stats" path={path} keyPath="/stats" isMinimized />
|
||||
)}
|
||||
{checkAccess(user, getTypesOfUser(["agent"]), permissions, "viewRecords") && (
|
||||
<Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" isMinimized />
|
||||
)}
|
||||
{checkAccess(user, getTypesOfUser(["agent"]), permissions, "viewRecords") && (
|
||||
<Nav disabled={disableNavigation} Icon={CiDumbbell} label="Training" path={path} keyPath="/training" isMinimized />
|
||||
)}
|
||||
{checkAccess(user, getTypesOfUser(["student"])) && (
|
||||
<Nav disabled={disableNavigation} Icon={BsShieldFill} label="Settings" path={path} keyPath="/settings" isMinimized />
|
||||
)}
|
||||
{entitiesAllowGeneration.length > 0 && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsCloudFill}
|
||||
label="Generation"
|
||||
path={path}
|
||||
keyPath="/generation"
|
||||
isMinimized
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
const neededPermissions = permissions.reduce((acc, curr) => {
|
||||
if (
|
||||
["viewExams", "viewRecords", "viewTickets"].includes(curr as string)
|
||||
) {
|
||||
acc.push(curr);
|
||||
}
|
||||
return acc;
|
||||
}, [] as PermissionType[]);
|
||||
|
||||
<div className="2xl:fixed bottom-12 flex flex-col gap-0 -2xl:mt-8">
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={1}
|
||||
onClick={toggleMinimize}
|
||||
className={clsx(
|
||||
"hover:text-mti-rose -xl:hidden flex cursor-pointer items-center gap-4 rounded-full p-4 text-black transition duration-300 ease-in-out",
|
||||
isMinimized ? "w-fit" : "w-full min-w-[250px] px-8",
|
||||
)}>
|
||||
{isMinimized ? <BsChevronBarRight size={24} /> : <BsChevronBarLeft size={24} />}
|
||||
{!isMinimized && <span className="text-lg font-medium">Minimize</span>}
|
||||
</div>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={1}
|
||||
onClick={focusMode ? () => { } : logout}
|
||||
className={clsx(
|
||||
"hover:text-mti-rose flex cursor-pointer items-center gap-4 rounded-full p-4 text-black transition duration-300 ease-in-out",
|
||||
isMinimized ? "w-fit" : "w-full min-w-[250px] px-8",
|
||||
)}>
|
||||
<RiLogoutBoxFill size={24} />
|
||||
{!isMinimized && <span className="-xl:hidden text-lg font-medium">Log Out</span>}
|
||||
</div>
|
||||
</div>
|
||||
{focusMode && <FocusLayer onFocusLayerMouseEnter={onFocusLayerMouseEnter} />}
|
||||
</section>
|
||||
);
|
||||
if (
|
||||
["student", "teacher", "developer"].includes(user.type) &&
|
||||
neededPermissions.includes("viewExams")
|
||||
) {
|
||||
sidebarPermissions["viewExams"] = true;
|
||||
}
|
||||
if (
|
||||
getTypesOfUser(["agent"]).includes(user.type) &&
|
||||
(entitiesAllowStatistics.length > 0 ||
|
||||
neededPermissions.includes("viewStats"))
|
||||
) {
|
||||
sidebarPermissions["viewStats"] = true;
|
||||
}
|
||||
if (
|
||||
[
|
||||
"admin",
|
||||
"developer",
|
||||
"teacher",
|
||||
"corporate",
|
||||
"mastercorporate",
|
||||
].includes(user.type) &&
|
||||
(entitiesAllowGeneration.length > 0 || isAdmin)
|
||||
) {
|
||||
sidebarPermissions["viewGeneration"] = true;
|
||||
}
|
||||
if (
|
||||
getTypesOfUser(["agent"]).includes(user.type) &&
|
||||
neededPermissions.includes("viewRecords")
|
||||
) {
|
||||
sidebarPermissions["viewRecords"] = true;
|
||||
}
|
||||
if (
|
||||
["admin", "developer", "agent"].includes(user.type) &&
|
||||
neededPermissions.includes("viewTickets")
|
||||
) {
|
||||
sidebarPermissions["viewTickets"] = true;
|
||||
}
|
||||
if (
|
||||
[
|
||||
"admin",
|
||||
"mastercorporate",
|
||||
"developer",
|
||||
"corporate",
|
||||
"teacher",
|
||||
"student",
|
||||
].includes(user.type)
|
||||
) {
|
||||
sidebarPermissions["viewClassrooms"] = true;
|
||||
}
|
||||
if (getTypesOfUser(["student", "agent"]).includes(user.type)) {
|
||||
sidebarPermissions["viewSettings"] = true;
|
||||
}
|
||||
if (
|
||||
["admin", "developer", "agent", "corporate", "mastercorporate"].includes(
|
||||
user.type
|
||||
) &&
|
||||
entitiesAllowPaymentRecord.length > 0
|
||||
) {
|
||||
sidebarPermissions["viewPaymentRecord"] = true;
|
||||
}
|
||||
return sidebarPermissions;
|
||||
}, [
|
||||
entitiesAllowGeneration.length,
|
||||
entitiesAllowPaymentRecord.length,
|
||||
entitiesAllowStatistics.length,
|
||||
isAdmin,
|
||||
permissions,
|
||||
user,
|
||||
]);
|
||||
|
||||
const { totalAssignedTickets } = useTicketsListener(
|
||||
user.id,
|
||||
sidebarPermissions["viewTickets"]
|
||||
);
|
||||
|
||||
const logout = async () => {
|
||||
axios.post("/api/logout").finally(() => {
|
||||
setTimeout(() => router.reload(), 500);
|
||||
});
|
||||
};
|
||||
|
||||
const disableNavigation = preventNavigation(navDisabled, focusMode);
|
||||
|
||||
return (
|
||||
<section
|
||||
className={clsx(
|
||||
"relative flex h-full flex-col justify-between bg-transparent px-4 py-4 pb-8",
|
||||
isMinimized ? "w-fit" : "-xl:w-fit w-1/6",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="-xl:hidden flex-col gap-3 xl:flex">
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={MdSpaceDashboard}
|
||||
label="Dashboard"
|
||||
path={path}
|
||||
keyPath="/dashboard"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
{sidebarPermissions["viewExams"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsFileEarmarkText}
|
||||
label="Practice"
|
||||
path={path}
|
||||
keyPath="/exam"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewStats"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsGraphUp}
|
||||
label="Stats"
|
||||
path={path}
|
||||
keyPath="/stats"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewClassrooms"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsPeople}
|
||||
label="Classrooms"
|
||||
path={path}
|
||||
keyPath="/classrooms"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewRecords"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsClockHistory}
|
||||
label="Record"
|
||||
path={path}
|
||||
keyPath="/record"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewRecords"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={CiDumbbell}
|
||||
label="Training"
|
||||
path={path}
|
||||
keyPath="/training"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewPaymentRecords"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsCurrencyDollar}
|
||||
label="Payment Record"
|
||||
path={path}
|
||||
keyPath="/payment-record"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewSettings"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsShieldFill}
|
||||
label="Settings"
|
||||
path={path}
|
||||
keyPath="/settings"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewTickets"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsClipboardData}
|
||||
label="Tickets"
|
||||
path={path}
|
||||
keyPath="/tickets"
|
||||
isMinimized={isMinimized}
|
||||
badge={totalAssignedTickets}
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewGeneration"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsCloudFill}
|
||||
label="Generation"
|
||||
path={path}
|
||||
keyPath="/generation"
|
||||
isMinimized={isMinimized}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="-xl:flex flex-col gap-3 xl:hidden">
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={MdSpaceDashboard}
|
||||
label="Dashboard"
|
||||
path={path}
|
||||
keyPath="/"
|
||||
isMinimized
|
||||
/>
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsFileEarmarkText}
|
||||
label="Exams"
|
||||
path={path}
|
||||
keyPath="/exam"
|
||||
isMinimized
|
||||
/>
|
||||
{sidebarPermissions["viewStats"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsGraphUp}
|
||||
label="Stats"
|
||||
path={path}
|
||||
keyPath="/stats"
|
||||
isMinimized
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewRecords"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsClockHistory}
|
||||
label="Record"
|
||||
path={path}
|
||||
keyPath="/record"
|
||||
isMinimized
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewRecords"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={CiDumbbell}
|
||||
label="Training"
|
||||
path={path}
|
||||
keyPath="/training"
|
||||
isMinimized
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewSettings"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsShieldFill}
|
||||
label="Settings"
|
||||
path={path}
|
||||
keyPath="/settings"
|
||||
isMinimized
|
||||
/>
|
||||
)}
|
||||
{sidebarPermissions["viewGeneration"] && (
|
||||
<Nav
|
||||
disabled={disableNavigation}
|
||||
Icon={BsCloudFill}
|
||||
label="Generation"
|
||||
path={path}
|
||||
keyPath="/generation"
|
||||
isMinimized
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="2xl:fixed bottom-12 flex flex-col gap-0 -2xl:mt-8">
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={1}
|
||||
onClick={toggleMinimize}
|
||||
className={clsx(
|
||||
"hover:text-mti-rose -xl:hidden flex cursor-pointer items-center gap-4 rounded-full p-4 text-black transition duration-300 ease-in-out",
|
||||
isMinimized ? "w-fit" : "w-full min-w-[250px] px-8"
|
||||
)}
|
||||
>
|
||||
{isMinimized ? (
|
||||
<BsChevronBarRight size={24} />
|
||||
) : (
|
||||
<BsChevronBarLeft size={24} />
|
||||
)}
|
||||
{!isMinimized && (
|
||||
<span className="text-lg font-medium">Minimize</span>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={1}
|
||||
onClick={focusMode ? () => {} : logout}
|
||||
className={clsx(
|
||||
"hover:text-mti-rose flex cursor-pointer items-center gap-4 rounded-full p-4 text-black transition duration-300 ease-in-out",
|
||||
isMinimized ? "w-fit" : "w-full min-w-[250px] px-8"
|
||||
)}
|
||||
>
|
||||
<RiLogoutBoxFill size={24} />
|
||||
{!isMinimized && (
|
||||
<span className="-xl:hidden text-lg font-medium">Log Out</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{focusMode && (
|
||||
<FocusLayer onFocusLayerMouseEnter={onFocusLayerMouseEnter} />
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user