diff --git a/apps/web/public/locales/en.json b/apps/web/public/locales/en.json index da9ad3842..e4289c7ee 100644 --- a/apps/web/public/locales/en.json +++ b/apps/web/public/locales/en.json @@ -482,6 +482,7 @@ "submitReviewInfo": "You have to submit a review to have access to this feature.", "tweetText": "Thrilled to have completed {{courseId}} course at @planb_network and earned my diploma with a score of {{score}}/100 on the final exam! {{emoji}} #PBNDiploma\n\n{{certificateUrl}}" }, + "courseDashboard": "Course dashboard", "courses": "Courses", "logout": "Log out", "myCourses": { @@ -539,6 +540,7 @@ "security": "Security", "username": "Username" }, + "studentDashboard": "Student dashboard", "teacher": { "courses": { "analytics": "Analytics", @@ -789,6 +791,7 @@ "buildersDescription": "Learn about the companies and projects that work at improving Bitcoin and increasing its adoption", "businessDescription": "Uncover Bitcoin usage in commerce.", "channelsDescription": "Access our exclusive selection of Youtube channels to learn about Bitcoin", + "chooseLanguage": "Choose a language", "conferencesDescription": "Collection of Bitcoin conference replays since the Genesis Block", "exchangesDescription": "Buy and sell bitcoins on exchanges and learn about P2P", "glossaryDescription": "Understand the language of Bitcoin", diff --git a/apps/web/src/assets/icons/profile_log_in_black.svg b/apps/web/src/assets/icons/profile_log_in_black.svg new file mode 100644 index 000000000..d58c44276 --- /dev/null +++ b/apps/web/src/assets/icons/profile_log_in_black.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/web/src/assets/icons/profile_log_in_white.svg b/apps/web/src/assets/icons/profile_log_in_white.svg new file mode 100644 index 000000000..61cf5f169 --- /dev/null +++ b/apps/web/src/assets/icons/profile_log_in_white.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/web/src/components/Header/MobileMenu/mobile-menu-section-elements.tsx b/apps/web/src/components/Header/MobileMenu/mobile-menu-section-elements.tsx new file mode 100644 index 000000000..649920475 --- /dev/null +++ b/apps/web/src/components/Header/MobileMenu/mobile-menu-section-elements.tsx @@ -0,0 +1,53 @@ +import { Link } from '@tanstack/react-router'; + +import { cn } from '@blms/ui'; + +import type { NavigationElementMobile } from '../props.ts'; + +export interface MobileMenuSectionElementProps { + element: NavigationElementMobile; +} + +export const MobileMenuSectionElement = ({ + element, +}: MobileMenuSectionElementProps) => { + return 'action' in element ? ( + + ) : ( + + {typeof element.icon === 'string' ? ( + {element.title} + ) : ( + element.icon + )} + {element.title} + + ); +}; diff --git a/apps/web/src/components/Header/MobileMenu/mobile-menu-section.tsx b/apps/web/src/components/Header/MobileMenu/mobile-menu-section.tsx index 032cf5562..7cea50336 100644 --- a/apps/web/src/components/Header/MobileMenu/mobile-menu-section.tsx +++ b/apps/web/src/components/Header/MobileMenu/mobile-menu-section.tsx @@ -2,108 +2,86 @@ import { Link } from '@tanstack/react-router'; import { useMemo } from 'react'; import { FiChevronDown } from 'react-icons/fi'; +import { cn } from '@blms/ui'; + import { useDisclosure } from '../../../hooks/use-disclosure.ts'; import { compose } from '../../../utils/index.ts'; -import { MenuElement } from '../menu-elements.tsx'; -import type { NavigationSection } from '../props.ts'; +import type { NavigationSectionMobile } from '../props.ts'; -import { MobileMenuSubSection } from './mobile-menu-sub-section.tsx'; +import { MobileMenuSectionElement } from './mobile-menu-section-elements.tsx'; export interface MobileMenuSectionProps { - section: NavigationSection; + section: NavigationSectionMobile; } -const buttonClasses = - 'flex flex-row justify-between py-3 px-4 my-2 w-full text-left text-gray-500 rounded-md border border-gray-200 border-solid duration-500 cursor-pointer'; - export const MobileMenuSection = ({ section }: MobileMenuSectionProps) => { const { toggle, isOpen } = useDisclosure(); - const currentSection = '/'.concat( - window.location.pathname.split('/').slice(2, 3).join(''), - ); const sectionTitle = useMemo(() => { if ('path' in section) { - const currentSectionClasses = - currentSection && - currentSection !== '/' && - section.path.includes(currentSection) - ? 'bg-darkOrange-9 text-white is-current' - : ''; - return ( {section.mobileIcon && ( )} - {section.title} + {section.title} ); } - if ('action' in section) - return ( - - ); return ( - ); - }, [isOpen, section, currentSection, toggle]); + }, [isOpen, section, toggle]); return ( -
  • +
  • {sectionTitle} {'items' in section && ( -
    - {section?.items?.map((subSectionOrElements, index) => - Array.isArray(subSectionOrElements) ? ( - - ) : ( - - ), +
    + {section?.items?.map((element) => ( + + ))}
    )}
  • diff --git a/apps/web/src/components/Header/MobileMenu/mobile-menu-sub-section.tsx b/apps/web/src/components/Header/MobileMenu/mobile-menu-sub-section.tsx deleted file mode 100644 index 611a96be1..000000000 --- a/apps/web/src/components/Header/MobileMenu/mobile-menu-sub-section.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { FiChevronDown } from 'react-icons/fi'; - -import { useDisclosure } from '../../../hooks/use-disclosure.ts'; -import { compose } from '../../../utils/index.ts'; -import { MenuElement } from '../menu-elements.tsx'; -import type { NavigationSubSection } from '../props.ts'; - -export interface MobileMenuSubSectionProps { - subSection: NavigationSubSection; -} - -export const MobileMenuSubSection = ({ - subSection, -}: MobileMenuSubSectionProps) => { - const { toggle, isOpen } = useDisclosure(); - - return ( -
    - -
    - {'items' in subSection && - subSection.items.map((element, index) => ( - - ))} -
    -
    - ); -}; diff --git a/apps/web/src/components/Header/MobileMenu/mobile-menu.tsx b/apps/web/src/components/Header/MobileMenu/mobile-menu.tsx index 75db5d303..727ef60e5 100644 --- a/apps/web/src/components/Header/MobileMenu/mobile-menu.tsx +++ b/apps/web/src/components/Header/MobileMenu/mobile-menu.tsx @@ -1,148 +1,31 @@ -import { Link, useNavigate } from '@tanstack/react-router'; -import { useContext, useEffect, useRef, useState } from 'react'; +import { Link, useLocation } from '@tanstack/react-router'; +import { useContext, useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; -import { AiOutlineBook } from 'react-icons/ai'; -import { BsMortarboard } from 'react-icons/bs'; -import { FaBars, FaRegCalendarCheck } from 'react-icons/fa'; -import { IoPersonOutline, IoTicketOutline } from 'react-icons/io5'; -import { LuLogOut } from 'react-icons/lu'; -import { MdKeyboardArrowDown } from 'react-icons/md'; +import { HiMiniBars3 } from 'react-icons/hi2'; +import { IoMdClose } from 'react-icons/io'; import { cn } from '@blms/ui'; import { AppContext } from '#src/providers/context.js'; +import { MenuDashboard } from '#src/routes/dashboard/_dashboard/-components/menu-dashboard.tsx'; import { getPictureUrl } from '#src/services/user.js'; -import { logout } from '#src/utils/session-utils.js'; import SignInIconDark from '../../../assets/icons/profile_log_in_dark.svg'; -import SignInIconDarkOrange from '../../../assets/icons/profile_log_in_darkOrange.svg'; import SignInIconLight from '../../../assets/icons/profile_log_in_light.svg'; import PlanBLogoOrange from '../../../assets/logo/planb_logo_horizontal_white_orangepill_whitetext.svg?react'; import PlanBLogoWhite from '../../../assets/logo/planb_logo_horizontal_white_whitepill.svg?react'; import { useDisclosure } from '../../../hooks/index.ts'; -import { LanguageSelector } from '../language-selector.tsx'; -import type { NavigationSection } from '../props.ts'; +import { LanguageSelectorMobile } from '../language-selector.tsx'; +import type { NavigationSectionMobile } from '../props.ts'; import { MobileMenuSection } from './mobile-menu-section.tsx'; export interface MobileMenuProps { - sections: NavigationSection[]; + sections: NavigationSectionMobile[]; onClickLogin: () => void; variant?: 'light' | 'dark'; } -interface LoggedMenuProps { - onClickLogin: () => void; -} - -const LoggedMenu = ({ onClickLogin }: LoggedMenuProps) => { - const { t } = useTranslation(); - const { user } = useContext(AppContext); - const pictureUrl = getPictureUrl(user); - const isLoggedIn = user?.uid !== undefined; - const [isSubMenuOpen, setIsSubMenuOpen] = useState(true); - - const navigate = useNavigate(); - - const toggleSubMenu = () => { - setIsSubMenuOpen((prev) => !prev); - }; - - const menuItems = [ - { - buttonText: t('words.courses'), - link: '/dashboard/courses', - icon: , - }, - { - buttonText: t('dashboard.calendar.calendar'), - link: '/dashboard/calendar', - icon: , - }, - { - buttonText: t('words.bookings'), - link: '/dashboard/bookings', - icon: , - }, - { - buttonText: t('words.credentials'), - link: '/dashboard/credentials', - icon: , - }, - { - buttonText: t('words.account'), - link: '/dashboard/profile', - icon: , - }, - ]; - - return ( -
    - {isLoggedIn && ( - <> - - {isSubMenuOpen && ( -
    - {menuItems.map((item) => ( - - {item.icon} - {item.buttonText} - - ))} - -
    - )} - - )} - - {!isLoggedIn && ( - - )} -
    - ); -}; - export const MobileMenu = ({ sections, onClickLogin, @@ -150,27 +33,39 @@ export const MobileMenu = ({ }: MobileMenuProps) => { const { isOpen: isMobileMenuOpen, toggle: toggleMobileMenu } = useDisclosure(); + const { isOpen: isDashboardMenuOpen, toggle: toggleDashboardMenu } = + useDisclosure(); const { t } = useTranslation(); const { session, user } = useContext(AppContext); const isLoggedIn = !!session; const mobileMenuRef = useRef(null); + const dashboardMenuRef = useRef(null); const pictureUrl = getPictureUrl(user); + const location = useLocation(); + useEffect(() => { - document.body.style.overflow = isMobileMenuOpen ? 'hidden' : 'auto'; + document.body.style.overflow = + isMobileMenuOpen || isDashboardMenuOpen ? 'hidden' : 'auto'; const handleClickOutside = (event: MouseEvent) => { if ( mobileMenuRef.current && - !mobileMenuRef.current.contains(event.target as Node) - ) { + !mobileMenuRef.current.contains(event.target as Node) && + isMobileMenuOpen + ) toggleMobileMenu(); - } + if ( + dashboardMenuRef.current && + !dashboardMenuRef.current.contains(event.target as Node) && + isDashboardMenuOpen + ) + toggleDashboardMenu(); }; - if (isMobileMenuOpen) { + if (isMobileMenuOpen || isDashboardMenuOpen) { document.addEventListener('mousedown', handleClickOutside); } else { document.removeEventListener('mousedown', handleClickOutside); @@ -179,15 +74,26 @@ export const MobileMenu = ({ return () => { document.removeEventListener('mousedown', handleClickOutside); }; - }, [isMobileMenuOpen, toggleMobileMenu]); + }, [ + isMobileMenuOpen, + isDashboardMenuOpen, + toggleMobileMenu, + toggleDashboardMenu, + ]); + + useEffect(() => { + if (isMobileMenuOpen && isDashboardMenuOpen) { + toggleDashboardMenu(); + } + }, [isMobileMenuOpen, isDashboardMenuOpen, toggleDashboardMenu]); return ( <> -
    +
    - @@ -203,32 +109,33 @@ export const MobileMenu = ({ {variant === 'light' ? ( - + ) : ( - + )} {isLoggedIn ? ( -
    - - - +
    +
    ) : ( -
    +
    @@ -245,39 +152,56 @@ export const MobileMenu = ({ + + {isLoggedIn && ( + + )} ); }; diff --git a/apps/web/src/components/Header/header.tsx b/apps/web/src/components/Header/header.tsx index 2da0ace37..7ca0be025 100644 --- a/apps/web/src/components/Header/header.tsx +++ b/apps/web/src/components/Header/header.tsx @@ -1,8 +1,13 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { LuMessageSquareMore } from 'react-icons/lu'; +import { MdOutlineSchool, MdPeopleAlt } from 'react-icons/md'; +import { TbWorld } from 'react-icons/tb'; import { cn } from '@blms/ui'; +import profileLogInBlack from '#src/assets/icons/profile_log_in_black.svg'; +import profileLogInWhite from '#src/assets/icons/profile_log_in_white.svg'; import resourcesSvg from '#src/assets/resources/builder.svg'; import eventsSvg from '#src/assets/resources/conference.svg'; import glossarySvg from '#src/assets/resources/glossary.svg'; @@ -25,7 +30,7 @@ import { AuthModalState } from '../AuthModals/props.ts'; import { FlyingMenu } from './FlyingMenu/flying-menu.tsx'; import { MobileMenu } from './MobileMenu/mobile-menu.tsx'; -import type { NavigationSection } from './props.ts'; +import type { NavigationSection, NavigationSectionMobile } from './props.ts'; interface HeaderProps { variant?: 'light' | 'dark'; @@ -239,7 +244,7 @@ export const Header = ({ variant = 'dark' }: HeaderProps) => { }, ]; - const mobileSections: NavigationSection[] = [ + const mobileSections: NavigationSectionMobile[] = [ { id: 'courses', title: t('words.courses'), @@ -267,15 +272,51 @@ export const Header = ({ variant = 'dark' }: HeaderProps) => { { id: 'about-us', title: t('words.about'), - path: '/about', mobileIcon: aboutSvg, + items: [ + { + id: 'professors', + title: t('words.professors'), + description: t('menu.teachersDescription'), + path: '/professors', + icon: , + }, + { + id: 'node-network', + title: t('words.nodeNetwork'), + description: t('menu.nodeNetworkDescription'), + path: '/node-network', + icon: , + }, + { + id: 'b-certificate', + title: t('words.bCertificate'), + description: t('menu.bCertificateDescription'), + path: '/b-certificate', + icon: , + }, + { + id: 'public-release', + title: t('words.public'), + description: t('menu.publicDescription'), + path: '/public-communication', + icon: , + }, + ], + }, + { + id: 'dashboard', + title: t('dashboard.studentDashboard'), + path: '/dashboard/courses', + mobileIcon: variant === 'light' ? profileLogInBlack : profileLogInWhite, + removeFilterOnIcon: true, }, ]; return (
    diff --git a/apps/web/src/components/Header/language-selector.tsx b/apps/web/src/components/Header/language-selector.tsx index e9a8169c3..76a26ffa4 100644 --- a/apps/web/src/components/Header/language-selector.tsx +++ b/apps/web/src/components/Header/language-selector.tsx @@ -1,7 +1,7 @@ import { useContext, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { FaArrowRightLong } from 'react-icons/fa6'; -import { MdKeyboardArrowDown } from 'react-icons/md'; +import { MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md'; import { Button, Popover, PopoverContent, PopoverTrigger, cn } from '@blms/ui'; @@ -138,3 +138,90 @@ export const LanguageSelector = ({ ); }; + +export const LanguageSelectorMobile = ({ + mode = 'dark', +}: { + mode?: 'light' | 'dark'; +}) => { + const { t, i18n } = useTranslation(); + const { setCurrentLanguage } = useContext(LangContext); + + const [open, setOpen] = useState(false); + + const activeLanguage = i18n.language ?? 'en'; + + const changeLanguage = (lang: string) => { + const pathName = location.pathname.slice(location.pathname.indexOf('/', 2)); + + router.update({ + basepath: lang, + context: router.options.context, + }); + + router.navigate({ + to: pathName + location.hash, + }); + + router.load(); + + setCurrentLanguage(lang); + setOpen(false); + }; + + return ( + + + + + e.stopPropagation()} + > + {LANGUAGES.filter( + (language) => language.toLowerCase() !== activeLanguage.toLowerCase(), + ).map((language) => ( + + ))} + + + ); +}; diff --git a/apps/web/src/components/Header/props.ts b/apps/web/src/components/Header/props.ts index e92963acf..e9accdc60 100644 --- a/apps/web/src/components/Header/props.ts +++ b/apps/web/src/components/Header/props.ts @@ -2,6 +2,7 @@ export interface NavigationBaseItem { id: string; title?: string; mobileIcon?: string; + removeFilterOnIcon?: boolean; } type ActionOrPath = { action: () => void } | { path: string }; @@ -16,3 +17,12 @@ export type NavigationSubSection = NavigationBaseItem & ({ action: () => void } | { path: string } | { items: NavigationElement[] }); export type NavigationSection = NavigationBaseItem & (ActionOrPath | { items: Array }); + +// Mobile specific +export type NavigationElementMobile = (NavigationBaseItem & { + icon?: string | React.ReactNode; + description?: string; +}) & + ActionOrPath; +export type NavigationSectionMobile = NavigationBaseItem & + (ActionOrPath | { items: NavigationElementMobile[] }); diff --git a/apps/web/src/routes/dashboard/_dashboard.tsx b/apps/web/src/routes/dashboard/_dashboard.tsx index 7b35c3cdb..2381b42b0 100644 --- a/apps/web/src/routes/dashboard/_dashboard.tsx +++ b/apps/web/src/routes/dashboard/_dashboard.tsx @@ -5,8 +5,7 @@ import { cn } from '@blms/ui'; import { MainLayout } from '#src/components/main-layout.js'; import { useSmaller } from '#src/hooks/use-smaller.js'; -import { MenuDesktop } from './_dashboard/-components/menu-desktop.tsx'; -import { MenuMobile } from './_dashboard/-components/menu-mobile.tsx'; +import { MenuDashboard } from './_dashboard/-components/menu-dashboard.tsx'; export const Route = createFileRoute('/dashboard/_dashboard')({ component: Dashboard, @@ -29,13 +28,12 @@ function Dashboard() { >
    -
    ) : (
    - +
    diff --git a/apps/web/src/routes/dashboard/_dashboard/-components/menu-desktop.tsx b/apps/web/src/routes/dashboard/_dashboard/-components/menu-dashboard.tsx similarity index 70% rename from apps/web/src/routes/dashboard/_dashboard/-components/menu-desktop.tsx rename to apps/web/src/routes/dashboard/_dashboard/-components/menu-dashboard.tsx index 3a790ac2d..dae978d8a 100644 --- a/apps/web/src/routes/dashboard/_dashboard/-components/menu-desktop.tsx +++ b/apps/web/src/routes/dashboard/_dashboard/-components/menu-dashboard.tsx @@ -5,6 +5,7 @@ import { useContext, useEffect, useState } from 'react'; import { AiOutlineBook } from 'react-icons/ai'; import { BsMortarboard } from 'react-icons/bs'; import { FaRegCalendarCheck } from 'react-icons/fa'; +import { IoMdClose } from 'react-icons/io'; import { IoLogOutOutline, IoPersonOutline, @@ -12,6 +13,8 @@ import { } from 'react-icons/io5'; import { LuPencilRuler, LuShieldAlert } from 'react-icons/lu'; +import { Button } from '@blms/ui'; + import pill from '#src/assets/icons/orange_pill_color_gradient.svg'; import SignInIconLight from '#src/assets/icons/profile_log_in_light.svg'; import { AppContext } from '#src/providers/context.js'; @@ -22,13 +25,14 @@ import { trpc } from '#src/utils/trpc.ts'; import { MenuItem } from './menu-item.tsx'; -export const MenuDesktop = ({ +export const MenuDashboard = ({ location, + toggleMobileMenu, }: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - location: ParsedLocation; + location: ParsedLocation; + toggleMobileMenu?: () => void; }) => { - const { user } = useContext(AppContext); + const { user, courses: allCourses } = useContext(AppContext); const [pathname, setPathname] = useState(''); const { data: courses } = trpc.user.courses.getProgress.useQuery(undefined, { @@ -40,8 +44,11 @@ export const MenuDesktop = ({ ?.filter((course) => course.progressPercentage < 100) .map((course) => { return { - text: addSpaceToCourseId(course.courseId.toLocaleUpperCase()), + text: `${addSpaceToCourseId(course.courseId.toLocaleUpperCase())} - ${ + allCourses?.find((c) => c.id === course.courseId)?.name + }`, to: `/dashboard/course/${course.courseId}`, + onClick: toggleMobileMenu, }; }); @@ -53,11 +60,9 @@ export const MenuDesktop = ({ const navigate = useNavigate(); - const dashboardPath = '/dashboard/courses'; const credentialsPath = '/dashboard/credentials'; const bookingsPath = '/dashboard/bookings'; const calendarPath = '/dashboard/calendar'; - const coursesPath = '/dashboard/courses'; const profilePath = '/dashboard/profile'; const adminRolePath = '/dashboard/administration/role'; const adminTutorialsPath = '/dashboard/administration/tutorials'; @@ -76,39 +81,59 @@ export const MenuDesktop = ({ }, [location]); const Separator = () => ( -
    +
    ); return ( -
    +
    Orange pill -
    +
    avatar -

    +

    {user?.displayName}

    + {toggleMobileMenu && ( + + )}
    -
    +
    + } + showOnMobileOnly + /> } - active={ - pathname.includes(coursesPath) || pathname.endsWith(dashboardPath) - } dropdown={[ + { + text: t('words.dashboard'), + to: '/dashboard/courses', + onClick: toggleMobileMenu, + }, ...(inProgressCourses ?? []), ...(completedCourses && completedCourses.length > 0 - ? [{ text: 'Completed', to: '/dashboard/course/completed' }] + ? [ + { + text: t('dashboard.myCourses.completed'), + to: '/dashboard/course/completed', + onClick: toggleMobileMenu, + }, + ] : []), ]} /> @@ -117,6 +142,7 @@ export const MenuDesktop = ({ text={t('dashboard.calendar.calendar')} icon={} active={pathname.includes(calendarPath)} + onClick={toggleMobileMenu} /> @@ -124,6 +150,7 @@ export const MenuDesktop = ({ text={t('words.bookings')} icon={} active={pathname.includes(bookingsPath)} + onClick={toggleMobileMenu} /> @@ -131,6 +158,7 @@ export const MenuDesktop = ({ text={t('words.credentials')} icon={} active={pathname.includes(credentialsPath)} + onClick={toggleMobileMenu} /> @@ -138,48 +166,17 @@ export const MenuDesktop = ({ text={t('dashboard.account')} icon={} active={pathname.includes(profilePath)} + onClick={toggleMobileMenu} /> - {user && (user.role === 'admin' || user.role === 'superadmin') && ( - <> - - -

    - Admin menu -

    - - - } - active={pathname.includes(adminRolePath)} - /> - - - } - active={pathname.includes(adminTutorialsPath)} - /> - - - } - active={pathname.includes(adminBookingsPath)} - /> - - - )} - {user && (user.role === 'professor' || (['admin', 'superadmin'].includes(user.role) && user.professorId)) && ( <> -

    +

    {t('dashboard.teacher.menu')}

    @@ -187,6 +184,7 @@ export const MenuDesktop = ({ text={t('dashboard.profile.profile')} icon={} active={pathname.includes(professorProfilePath)} + onClick={toggleMobileMenu} /> {user.professorCourses?.length > 0 && ( @@ -195,6 +193,7 @@ export const MenuDesktop = ({ text={t('dashboard.courses')} icon={} active={pathname.includes(professorCoursesPath)} + onClick={toggleMobileMenu} /> )} @@ -204,23 +203,63 @@ export const MenuDesktop = ({ text={t('words.tutorials')} icon={} active={pathname.includes(professorTutorialsPath)} + onClick={toggleMobileMenu} /> )} )} + {user && (user.role === 'admin' || user.role === 'superadmin') && ( + <> + + +

    + Admin menu +

    + + + } + active={pathname.includes(adminRolePath)} + onClick={toggleMobileMenu} + /> + + + } + active={pathname.includes(adminTutorialsPath)} + onClick={toggleMobileMenu} + /> + + + } + active={pathname.includes(adminBookingsPath)} + onClick={toggleMobileMenu} + /> + + + )} + - } +
    ); diff --git a/apps/web/src/routes/dashboard/_dashboard/-components/menu-item.tsx b/apps/web/src/routes/dashboard/_dashboard/-components/menu-item.tsx index f28ff15e8..49d9dfc90 100644 --- a/apps/web/src/routes/dashboard/_dashboard/-components/menu-item.tsx +++ b/apps/web/src/routes/dashboard/_dashboard/-components/menu-item.tsx @@ -10,19 +10,21 @@ export const MenuItem = ({ active, onClick, dropdown, + showOnMobileOnly, }: { text: string; icon: React.ReactNode; active?: boolean; onClick?: () => void; - dropdown?: Array<{ text: string; to: string }>; + dropdown?: Array<{ text: string; to: string; onClick?: () => void }>; + showOnMobileOnly?: boolean; }) => { const [isOpen, setIsOpen] = useState(true); const location = useLocation(); return ( -