Im using nextjs 13, with an adminContextProvider i created that stores the state of the sidebar being open or closed with a function to toggle the state.
When i have the useOutsideClick hook connected to the sidebar with the if statement, I can no longer close the sidebar on mobile. I only want the click outside to work when in mobile.
When i remove
if (isMobile && isSidebarOpen) {
closeSidebar()
}
from sidebar.tsx, i can close the sidebar on mobile but then obviously the click outside doesn’t close the sidebar. I’m lost as to why that would interfere with trying to close the sidebar. If i press literally ANY other button on the page, the sidebar closes, but when i press the only button that has the closesidebar function, it doesn’t close. I don’t know what I’m missing or overlooking, I really hope it’s something stupid and i apologize in advance for wasting anyone’s time.
Sidebar.tsx
import { HomeIcon } from '@radix-ui/react-icons'
import React, { useEffect, useState } from 'react'
import { Person } from 'react-bootstrap-icons'
import styled from 'styled-components'
import AdminSidebarToggle from '../AdminSidebarToggle'
import useAdminContext from '../../../context/adminContext/useAdminContext'
import Link from 'next/link'
import Image from 'next/image'
import useSettings from '../../../../../hooks/useSettings'
import { Avatar, Flex, Text } from '@radix-ui/themes'
import AdminMenu from '../admin-menu/AdminMenu'
import useMobileDetect from '../../../../../hooks/useMobileDetect'
import useOutsideClick from '../../../../../hooks/useClickOutside'
const { version } = require('../../../../../../package.json')
const SidebarContainer = styled.div<{ isCollapsed: boolean }>`
// width: ${({ isCollapsed }) => (isCollapsed ? '0rem' : '14rem')};
height: 100vh;
background: linear-gradient(180deg, var(--slate-2) 0%, var(--slate-2) 42%, var(--slate-2) 100%);
transition: all 0.5s cubic-bezier(0.87, 0, 0.13, 1);
display: flex;
flex-direction: column;
align-items: center;
position: fixed;
z-index: 1000;
// margin-top: 60px;
border-right: 1px solid var(--slate-4);
// width: ${({ isCollapsed }) => (isCollapsed ? '0' : '14rem')};
position: fixed;
top: 0;
left: ${({ isCollapsed }) => (isCollapsed ? '-14rem' : '0rem')};
bottom: 0;
overflow-x: hidden;
`
const Sidebar: React.FC = () => {
const {
state: { isSidebarOpen, themeMode },
closeSidebar,
openSidebar,
toggleSidebar,
} = useAdminContext()
const { settings }: any = useSettings()
const { isMobile } = useMobileDetect()
useEffect(() => {
if (isMobile) {
closeSidebar()
} else {
openSidebar()
}
}, [isMobile])
const ref = useOutsideClick(() => {
if (isMobile && isSidebarOpen) {
closeSidebar()
}
})
return (
<SidebarContainer ref={ref} isCollapsed={!isSidebarOpen}>
{/* <ToggleButton onClick={toggleSidebar}>{isCollapsed ? '☰' : '✖'}</ToggleButton> */}
<Flex direction="column" py="2" mb="4" gap="1" style={{ minHeight: '60px' }}>
<Link href="/" target="_blank">
<div style={{ position: 'relative', width: '200px', height: '52px' }}>
<Image
alt="Logo"
src={
themeMode === 'dark'
? settings['main_logo_alt']?.value
: settings['main_logo']?.value
}
layout="fill"
objectFit="contain"
quality={100}
/>
</div>
</Link>
<div className={`subHeader text-center`}>
<Text className="text-nowrap">{settings['company_name']?.value}</Text>
</div>
</Flex>
<AdminMenu />
</SidebarContainer>
)
}
export default Sidebar
Toggle
import { DoubleArrowLeftIcon } from '@radix-ui/react-icons'
import styled from 'styled-components'
import useAdminContext from '../../context/adminContext/useAdminContext'
import { Button, Flex } from '@radix-ui/themes'
import useMobileDetect from '../../../../hooks/useMobileDetect'
import { useEffect } from 'react'
const Icon = styled(DoubleArrowLeftIcon)<{ isSidebarOpen: boolean }>`
cursor: pointer;
width: 24px;
height: 24px;
transition: transform 0.3s;
transform: ${(props) => (!props.isSidebarOpen ? 'rotate(180deg)' : 'rotate(0deg)')};
`
const AdminSidebarToggle = () => {
const {
state: { isSidebarOpen },
toggleSidebar,
closeSidebar,
openSidebar,
} = useAdminContext()
const { isMobile } = useMobileDetect()
useEffect(() => {
if (!isMobile && !isSidebarOpen) {
openSidebar()
} else if (isMobile && isSidebarOpen) {
closeSidebar()
}
}, [isMobile])
useEffect(() => {
console.log(" toggle isSidebarOpen", isSidebarOpen)
}, [isSidebarOpen])
return (
<Button size="3" color="gray" variant="ghost" onClick={() => {
console.log("isSidebarOpen", isSidebarOpen)
if(isSidebarOpen){
console.log("YOURE SUPPOSED TO CLOSE!!!!!!")
closeSidebar()
} else {
openSidebar()
}
}}>
<Icon isSidebarOpen={isSidebarOpen} />
</Button>
)
}
export default AdminSidebarToggle
usOutsideClick
import { useRef, useEffect, RefObject } from 'react'
const useOutsideClick = (callback: () => void): RefObject<any> => {
const ref = useRef<any>(null)
useEffect(() => {
const handleClick = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
callback()
}
}
document.addEventListener('click', handleClick, true)
return () => {
document.removeEventListener('click', handleClick, true)
}
}, [callback])
return ref
}
export default useOutsideClick