182 lines
6.0 KiB
TypeScript
182 lines
6.0 KiB
TypeScript
'use client'
|
|
|
|
// React Imports
|
|
import { useRef, useState } from 'react'
|
|
import type { MouseEvent } from 'react'
|
|
|
|
// Next Imports
|
|
import { useParams, useRouter } from 'next/navigation'
|
|
|
|
// MUI Imports
|
|
import { styled } from '@mui/material/styles'
|
|
import Badge from '@mui/material/Badge'
|
|
import Avatar from '@mui/material/Avatar'
|
|
import Popper from '@mui/material/Popper'
|
|
import Fade from '@mui/material/Fade'
|
|
import Paper from '@mui/material/Paper'
|
|
import ClickAwayListener from '@mui/material/ClickAwayListener'
|
|
import MenuList from '@mui/material/MenuList'
|
|
import Typography from '@mui/material/Typography'
|
|
import Divider from '@mui/material/Divider'
|
|
import MenuItem from '@mui/material/MenuItem'
|
|
import Button from '@mui/material/Button'
|
|
|
|
// Type Imports
|
|
import type { Locale } from '@configs/i18n'
|
|
|
|
// Hook Imports
|
|
import { useSettings } from '@core/hooks/useSettings'
|
|
|
|
// Util Imports
|
|
import { getLocalizedUrl } from '@/utils/i18n'
|
|
import { useAuthMutation } from '../../../services/mutations/auth'
|
|
import { useAuth } from '../../../contexts/authContext'
|
|
import { CircularProgress } from '@mui/material'
|
|
|
|
// Styled component for badge content
|
|
const BadgeContentSpan = styled('span')({
|
|
width: 8,
|
|
height: 8,
|
|
borderRadius: '50%',
|
|
cursor: 'pointer',
|
|
backgroundColor: 'var(--mui-palette-success-main)',
|
|
boxShadow: '0 0 0 2px var(--mui-palette-background-paper)'
|
|
})
|
|
|
|
const UserDropdown = () => {
|
|
const { currentUser } = useAuth()
|
|
|
|
// States
|
|
const [open, setOpen] = useState(false)
|
|
|
|
// Refs
|
|
const anchorRef = useRef<HTMLDivElement>(null)
|
|
|
|
const { logout } = useAuthMutation()
|
|
|
|
// Hooks
|
|
const router = useRouter()
|
|
const { settings } = useSettings()
|
|
const { lang: locale } = useParams()
|
|
|
|
const handleDropdownOpen = () => {
|
|
!open ? setOpen(true) : setOpen(false)
|
|
}
|
|
|
|
const handleDropdownClose = (event?: MouseEvent<HTMLLIElement> | (MouseEvent | TouchEvent), url?: string) => {
|
|
if (url) {
|
|
router.push(getLocalizedUrl(url, locale as Locale))
|
|
}
|
|
|
|
if (anchorRef.current && anchorRef.current.contains(event?.target as HTMLElement)) {
|
|
return
|
|
}
|
|
|
|
setOpen(false)
|
|
}
|
|
|
|
const handleUserLogout = async () => {
|
|
try {
|
|
// Sign out from the app
|
|
// await signOut({ callbackUrl: process.env.NEXT_PUBLIC_APP_URL })
|
|
logout.mutate()
|
|
router.push(getLocalizedUrl('/login', locale as Locale))
|
|
} catch (error) {
|
|
console.error(error)
|
|
|
|
// Show above error in a toast like following
|
|
// toastService.error((err as Error).message)
|
|
}
|
|
}
|
|
|
|
if (!currentUser) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Badge
|
|
ref={anchorRef}
|
|
overlap='circular'
|
|
badgeContent={<BadgeContentSpan onClick={handleDropdownOpen} />}
|
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
|
className='mis-2'
|
|
>
|
|
<Avatar
|
|
ref={anchorRef}
|
|
alt={'John doe'}
|
|
src={''}
|
|
onClick={handleDropdownOpen}
|
|
className='cursor-pointer bs-[38px] is-[38px]'
|
|
/>
|
|
</Badge>
|
|
<Popper
|
|
open={open}
|
|
transition
|
|
disablePortal
|
|
placement='bottom-end'
|
|
anchorEl={anchorRef.current}
|
|
className='min-is-[240px] !mbs-3 z-[1]'
|
|
>
|
|
{({ TransitionProps, placement }) => (
|
|
<Fade
|
|
{...TransitionProps}
|
|
style={{
|
|
transformOrigin: placement === 'bottom-end' ? 'right top' : 'left top'
|
|
}}
|
|
>
|
|
<Paper className={settings.skin === 'bordered' ? 'border shadow-none' : 'shadow-lg'}>
|
|
<ClickAwayListener onClickAway={e => handleDropdownClose(e as MouseEvent | TouchEvent)}>
|
|
<MenuList>
|
|
<div className='flex items-center plb-2 pli-6 gap-2' tabIndex={-1}>
|
|
<Avatar alt={'john doe'} src={''} />
|
|
<div className='flex items-start flex-col'>
|
|
<Typography className='font-medium' color='text.primary'>
|
|
{currentUser?.name}
|
|
</Typography>
|
|
<Typography variant='caption'>{currentUser?.email}</Typography>
|
|
</div>
|
|
</div>
|
|
<Divider className='mlb-1' />
|
|
<MenuItem className='mli-2 gap-3' onClick={e => handleDropdownClose(e, '/pages/user-profile')}>
|
|
<i className='tabler-user' />
|
|
<Typography color='text.primary'>My Profile</Typography>
|
|
</MenuItem>
|
|
<MenuItem className='mli-2 gap-3' onClick={e => handleDropdownClose(e, '/pages/account-settings')}>
|
|
<i className='tabler-settings' />
|
|
<Typography color='text.primary'>Settings</Typography>
|
|
</MenuItem>
|
|
<MenuItem className='mli-2 gap-3' onClick={e => handleDropdownClose(e, '/pages/pricing')}>
|
|
<i className='tabler-currency-dollar' />
|
|
<Typography color='text.primary'>Pricing</Typography>
|
|
</MenuItem>
|
|
<MenuItem className='mli-2 gap-3' onClick={e => handleDropdownClose(e, '/pages/faq')}>
|
|
<i className='tabler-help-circle' />
|
|
<Typography color='text.primary'>FAQ</Typography>
|
|
</MenuItem>
|
|
<div className='flex items-center plb-2 pli-3'>
|
|
<Button
|
|
fullWidth
|
|
variant='contained'
|
|
color='error'
|
|
size='small'
|
|
endIcon={<i className='tabler-logout' />}
|
|
onClick={handleUserLogout}
|
|
sx={{ '& .MuiButton-endIcon': { marginInlineStart: 1.5 } }}
|
|
disabled={logout.isPending}
|
|
>
|
|
Logout {logout.isPending && <CircularProgress size={16} />}
|
|
</Button>
|
|
</div>
|
|
</MenuList>
|
|
</ClickAwayListener>
|
|
</Paper>
|
|
</Fade>
|
|
)}
|
|
</Popper>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default UserDropdown
|