Instantly share code, notes, and snippets.
Created
July 9, 2025 12:22
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save muhsinazmal9/bd80669c77a2b5923aa40ed16f91a7b5 to your computer and use it in GitHub Desktop.
previous and cluttered one
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 'use client'; | |
| import { userDashboardSidebarMenuItems } from '@/localization/localization'; | |
| import Link from 'next/link'; | |
| import React, { useState, useEffect, useRef } from 'react'; | |
| import { FiMinus } from 'react-icons/fi'; | |
| import { FaChevronRight } from 'react-icons/fa6'; | |
| import { FaChevronLeft } from 'react-icons/fa'; | |
| import { useDispatch, useSelector } from 'react-redux'; | |
| import { miniSidebar } from '@/app/redux/sidebarSlice/sidebarSlice'; | |
| import { useRouter, usePathname, useSearchParams } from 'next/navigation'; | |
| import { apiCall, filterMenuByPermissions } from '../utils/utls'; | |
| import { useFilteredSidebar } from '@/hooks/useFilteredSidebar'; | |
| import { useGetPremiumCoursesQuery } from '@/app/redux/api/coursesApi'; | |
| import Skeleton from 'react-loading-skeleton'; | |
| import { useSidebar } from '@/hooks/useSidebar'; | |
| function Sidebar({ offCanvas = false, setShowSidebar = '' }) { | |
| // console.log('useSidebar', useSidebar()); | |
| // const sidebarItems = useSidebar(); | |
| const [loading, setLoading] = useState(false); | |
| const [resumeBuilderPage, setResumeBuilderPage] = useState(false); | |
| const searchParams = useSearchParams(); | |
| const [pagesList, setPagesList] = useState(null); | |
| const router = useRouter(); | |
| const pathname = usePathname(); | |
| const dispatch = useDispatch(); | |
| const [activeMenu, setActiveMenu] = useState(0); | |
| const [menuSelected, setMenuSelected] = useState(null); | |
| const [activeSubMenu, setActiveSubMenu] = useState(null); | |
| const [isMiniSidebar, setIsMiniSidebar] = useState(false); | |
| const is_amplify_for_cognify_enabled = useSelector( | |
| (state) => | |
| state?.aptitude?.aptitude?.category?.is_amplify_for_cognify_enabled ?? | |
| false | |
| ); | |
| const [finalMenuItems, setFinalMenuItems] = useState([]); | |
| const heightRef = useRef(null); | |
| const [height, setHeight] = useState('auto'); | |
| const { category } = useSelector((state) => state.aptitude.aptitude); | |
| const { setting } = useSelector((state) => state.settings); | |
| const { loggedInUser } = useSelector((state) => state.user); | |
| const { permissions } = useSelector((state) => state.user.userPermissions); | |
| const { active_campaign_permissions } = useSelector( | |
| (state) => state.user.loggedInUser | |
| ); | |
| const shouldShowMyCourses = permissions?.some( | |
| (item) => item.name === 'view_courses' | |
| ); | |
| // console.log('Sidebar permissions:', permissions); | |
| // console.log('active_campaign_permissions:', active_campaign_permissions); | |
| useEffect(() => { | |
| const params = new URLSearchParams(searchParams.toString()); | |
| const pageNumber = params.get('page'); | |
| userDashboardSidebarMenuItems.forEach((menu) => { | |
| if (menu.link === pathname) { | |
| setActiveMenu(menu.id); | |
| } | |
| menu.submenu?.forEach((subitem) => { | |
| if (subitem.link === pathname) { | |
| setActiveMenu(menu.id); | |
| setActiveSubMenu(subitem.id); | |
| } | |
| if ( | |
| pathname.startsWith('/dashboard/resume/builder') && | |
| subitem.link.startsWith('/dashboard/resume/builder') | |
| ) { | |
| if (pageNumber == subitem.id) { | |
| setActiveSubMenu(subitem.id); | |
| } | |
| } | |
| }); | |
| }); | |
| if (pathname.startsWith('/dashboard/resume/builder')) { | |
| if (activeMenu != 5) { | |
| setActiveMenu(5); | |
| } | |
| setResumeBuilderPage(true); | |
| } else { | |
| setResumeBuilderPage(false); | |
| } | |
| }, [category?.id, pathname, searchParams]); | |
| const handleResetScroll = () => { | |
| window.scrollTo({ top: 0, behavior: 'auto' }); | |
| }; | |
| const handleMenuClick = (menu) => { | |
| setActiveSubMenu(null); | |
| setActiveMenu(activeMenu === menu.id ? null : menu.id); | |
| setMenuSelected(activeMenu === menu.id ? activeMenu : null); | |
| dispatch(miniSidebar(false)); | |
| setIsMiniSidebar(false); | |
| if (menu?.submenu?.length > 0) { | |
| const filteredSubMenu = menu.submenu.filter((subItem) => { | |
| if ( | |
| subItem.name === 'Fire Service Exams' && | |
| is_amplify_for_cognify_enabled | |
| ) { | |
| return false; | |
| } | |
| if ( | |
| subItem.name === 'Amplify for Cognify' && | |
| !is_amplify_for_cognify_enabled | |
| ) { | |
| return false; | |
| } | |
| if ( | |
| menu.title == 'Aptitude' && | |
| subItem.name === 'Exam Results' && | |
| is_amplify_for_cognify_enabled | |
| ) { | |
| return false; | |
| } | |
| if ( | |
| subItem.name === 'Aptitude Specials' && | |
| loggedInUser?.membership?.toLowerCase() !== 'elite' | |
| ) { | |
| return false; | |
| } | |
| return true; | |
| }); | |
| } | |
| if (menu.title === 'Interview') { | |
| handleResetScroll(); | |
| const section = document.getElementById('interview'); | |
| if (section) { | |
| const offset = 170; | |
| const sectionTop = | |
| section.getBoundingClientRect().top + window.scrollY - offset; | |
| window.scrollTo({ top: sectionTop, behavior: 'smooth' }); | |
| } | |
| } | |
| if (menu.title === 'Personality') { | |
| handleResetScroll(); | |
| const section = document.getElementById('personality'); | |
| if (section) { | |
| const offset = 170; | |
| const sectionTop = | |
| section.getBoundingClientRect().top + window.scrollY - offset; | |
| window.scrollTo({ top: sectionTop, behavior: 'smooth' }); | |
| } | |
| } | |
| if (menu.title === 'Aptitude') { | |
| handleResetScroll(); | |
| const section = document.getElementById('aptitude'); | |
| if (section) { | |
| const offset = 170; | |
| const sectionTop = | |
| section.getBoundingClientRect().top + window.scrollY - offset; | |
| window.scrollTo({ top: sectionTop, behavior: 'smooth' }); | |
| } | |
| } | |
| }; | |
| const handleActiveSubMenu = (subitem) => { | |
| dispatch(miniSidebar(false)); | |
| setIsMiniSidebar(false); | |
| setActiveSubMenu(activeSubMenu === subitem.id ? subitem.id : subitem.id); | |
| setShowSidebar(false); | |
| router.push(subitem.link); | |
| }; | |
| const handleMiniSidebar = () => { | |
| setIsMiniSidebar(!isMiniSidebar); | |
| dispatch(miniSidebar(!isMiniSidebar)); | |
| setActiveMenu(null); | |
| }; | |
| const { data, isLoading } = useGetPremiumCoursesQuery(); | |
| // my courses menu items | |
| const myCoursesMenu = { | |
| id: 2, | |
| title: 'My Courses', | |
| iconBlack: '/assets/images/course.svg', | |
| iconWhite: '/assets/images/course-white.svg', | |
| link: '/dashboard/courses', | |
| permission: '', | |
| submenu: isLoading | |
| ? Array(4).fill({ isSkeleton: true }) | |
| : data?.data?.map((course) => ({ | |
| id: course.id, | |
| name: course.title, | |
| link: `/dashboard/courses/${course.id}`, | |
| permission: 'view_courses', | |
| })), | |
| }; | |
| // user role based menu items filtered | |
| const allowedMenuItems = useFilteredSidebar(); | |
| // Insert myCoursesMenu at index 1 or as a second item | |
| const updatedMenuItems = shouldShowMyCourses | |
| ? [ | |
| ...allowedMenuItems.slice(0, 1), | |
| myCoursesMenu, | |
| ...allowedMenuItems.slice(1), | |
| ] | |
| : [...allowedMenuItems]; | |
| const fullMenuList = [...updatedMenuItems]; | |
| useEffect(() => { | |
| if (pagesList == null) return; | |
| if (pagesList.length == 0) { | |
| setFinalMenuItems([...fullMenuList]); | |
| return; | |
| } | |
| fullMenuList.push( | |
| ...pagesList.map((pageMenu, index) => ({ | |
| id: index + 11, | |
| order: pageMenu.order, | |
| title: pageMenu.name, | |
| iconBlack: '/assets/images/page.svg', | |
| iconWhite: '/assets/images/page-white.svg', | |
| link: '', | |
| submenu: pageMenu?.pages?.map((page) => ({ | |
| id: page.id, | |
| name: page.title, | |
| link: `/dashboard/pages/${page.slug}`, | |
| permission: 'page_builder_section', | |
| })), | |
| })) | |
| ); | |
| let nextOrder = 1; | |
| const assignOrders = () => { | |
| const used = new Set( | |
| fullMenuList | |
| .map((i) => (i.order >= 1000 ? delete i.order : i.order)) | |
| .filter(Boolean) | |
| ); | |
| for (const item of fullMenuList) { | |
| if (item.order == null) { | |
| while (used.has(nextOrder)) nextOrder++; | |
| item.order = nextOrder++; | |
| } else { | |
| nextOrder = Math.max(nextOrder, item.order + 1); | |
| } | |
| } | |
| fullMenuList.sort((a, b) => a.order - b.order); | |
| setFinalMenuItems([...fullMenuList]); | |
| }; | |
| assignOrders(); | |
| }, [pagesList, data?.data?.length]); | |
| const getPagesList = async () => { | |
| if (!category?.id) return; | |
| const { success, data } = await apiCall( | |
| `/api/v2/page-menus`, | |
| 'GET', | |
| {}, | |
| setLoading | |
| ); | |
| if (success) { | |
| setPagesList(data); | |
| setLoading(false); | |
| return; | |
| } else { | |
| setPagesList([]); | |
| setLoading(false); | |
| } | |
| }; | |
| useEffect(() => { | |
| getPagesList(); | |
| }, [category?.id]); | |
| useEffect(() => { | |
| if (heightRef.current) { | |
| const baseHeight = heightRef.current.scrollHeight; | |
| setHeight(`${baseHeight + 500}px`); | |
| } | |
| }, []); | |
| return ( | |
| <div | |
| className={`${ | |
| offCanvas ? 'max-w-full' : 'max-w-[286px]' | |
| } !w-full h-full max-h-[92vh] overflow-y-auto scrollbar-custom`} | |
| > | |
| <aside className={`flex flex-col`}> | |
| <nav className="flex h-min pb-40 text-lg 2xl:text-xl font-medium text-colorBlack max-md:mt-5"> | |
| <div | |
| className={`flex flex-col grow shrink-0 px-4 xl:pt-11 pb-10 rounded-2xl basis-0 w-fit max-md:px-5 max-md:pb-24 relative ${ | |
| isMiniSidebar ? '!max-w-[100px]' : '!max-w-[286px] w-full ' | |
| }`} | |
| > | |
| {finalMenuItems?.length > 0 | |
| ? finalMenuItems.map((menu, index) => ( | |
| <div key={menu.id} className="menu-item"> | |
| <div | |
| className={`flex self-start justify-between items-center mb-4 md:mb-5 py-2 transition ease-linear duration-300 rounded-[30px] bg-white px-2 cursor-pointer select-none ${ | |
| activeMenu === menu.id || menuSelected === menu.id | |
| ? 'activeSidebarItem ' | |
| : '' | |
| }`} | |
| onClick={() => handleMenuClick(menu)} | |
| > | |
| <Link | |
| href={menu.link} | |
| className={`flex items-center transition ease-linear duration-200 ${ | |
| isMiniSidebar ? 'justify-center ps-5' : 'ps-0' | |
| } gap-3 2xl:gap-5 w-full`} | |
| > | |
| <img | |
| loading="lazy" | |
| src={ | |
| activeMenu === menu.id || menuSelected === menu.id | |
| ? menu.iconWhite | |
| : menu.iconBlack | |
| } | |
| alt="icon" | |
| className="object-contain shrink-0 my-auto w-7 aspect-[1.4]" | |
| /> | |
| { | |
| <span | |
| className={`${ | |
| activeMenu === menu.id | |
| ? '-' | |
| : ' hover:text-colorOrange' | |
| } hover-animate whitespace-nowrap `} | |
| style={{ | |
| opacity: !isMiniSidebar ? 1 : 0, | |
| visibility: !isMiniSidebar ? 'visible' : 'hidden', | |
| height: !isMiniSidebar ? 'auto' : 0, | |
| }} | |
| > | |
| {!isMiniSidebar ? menu.title : ''} | |
| </span> | |
| } | |
| </Link> | |
| {menu.submenu?.length > 0 && | |
| activeMenu === menu.id && | |
| !(menu.title === 'Resume' && !resumeBuilderPage) && ( | |
| <FiMinus /> | |
| )} | |
| </div> | |
| {menu.submenu && ( | |
| <div | |
| className="sub-menu-item flex flex-col max-w-full text-base 2xl:text-lg text-colorBlackSecond transition ease-linear duration-500 whitespace-nowrap ml-4 relative rounded" | |
| style={{ | |
| opacity: activeMenu === menu.id ? 1 : 0, | |
| visibility: | |
| activeMenu === menu.id ? 'visible' : 'hidden', | |
| height: activeMenu === menu.id ? 'auto' : 0, | |
| }} | |
| > | |
| {menu.submenu.map((subitem, subIndex) => { | |
| if (menu.id == 2 && subitem.isSkeleton) { | |
| return ( | |
| <div | |
| key={`skeleton-${subIndex}`} | |
| className="self-start mb-6 ps-[6px] w-[180px]" | |
| > | |
| <Skeleton height={20} borderRadius={4} /> | |
| </div> | |
| ); | |
| } | |
| if ( | |
| (subitem.name === 'Fire Service Exams' && is_amplify_for_cognify_enabled) ||(subitem.name === 'Fire Service Exams' && !setting?.exam_visibility) | |
| ) { | |
| return null; | |
| } | |
| if ( | |
| subitem.name === 'Amplify for Cognify' && | |
| !is_amplify_for_cognify_enabled | |
| ) { | |
| return null; | |
| } | |
| if ( | |
| menu.title == 'Aptitude' && | |
| subitem.name === 'Exam Results' && | |
| is_amplify_for_cognify_enabled | |
| ) { | |
| return null; | |
| } | |
| if ( | |
| subitem.name === 'Aptitude Specials' && | |
| loggedInUser?.membership?.toLowerCase() !== 'elite' | |
| ) { | |
| return null; | |
| } | |
| if ( | |
| subitem.type === 'resume_builder' && | |
| !resumeBuilderPage | |
| ) { | |
| return null; | |
| } | |
| const isLastItem = | |
| subIndex == menu.submenu.length - 1; | |
| return ( | |
| <Link | |
| onClick={() => handleActiveSubMenu(subitem)} | |
| key={subIndex} | |
| href={subitem.link || '/dashboard'} | |
| className={`self-start mb-5 hover:text-colorOrange hover-animate relative ps-[25px] ${ | |
| activeSubMenu === subitem.id | |
| ? 'font-bold text-colorOrange' | |
| : '' | |
| }`} | |
| > | |
| <img | |
| className="absolute -left-[4px] top-[50%] translate-y-[-50%]" | |
| src="/assets/images/icons/curve.svg" | |
| alt="curve" | |
| /> | |
| <span | |
| className={`absolute -left-[3px] top-[50%] translate-y-[-50%] border-l border-[1.75px] border-[#D1D1D1] h-[48px] ${ | |
| isLastItem ? '!h-[20px] !top-0' : '' | |
| }`} | |
| ></span> | |
| <span className="block max-w-[220px] truncate whitespace-nowrap overflow-hidden text-ellipsis"> | |
| {subitem.name} | |
| </span> | |
| </Link> | |
| ); | |
| })} | |
| </div> | |
| )} | |
| </div> | |
| )) | |
| : Array(10) | |
| .fill({ isSkeleton: true }) | |
| .map((item, index) => ( | |
| <div key={index} className="menu-item mb-5"> | |
| <Skeleton height={40} borderRadius={8} /> | |
| </div> | |
| ))} | |
| </div> | |
| </nav> | |
| </aside> | |
| {!offCanvas && ( | |
| <div onClick={handleMiniSidebar} className="mini-sidebar-toggler"> | |
| {isMiniSidebar ? ( | |
| <FaChevronRight size={16} /> | |
| ) : ( | |
| <FaChevronLeft size={16} /> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } | |
| export default Sidebar; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment