farmcontrol-ui/src/components/Dashboard/common/UserProfilePopover.jsx
Tom Butcher 775393dfd1
Some checks failed
farmcontrol/farmcontrol-ui/pipeline/head There was a failure building this commit
Add user profile popover and logout icon; refactor dashboard navigation
2026-03-07 19:22:21 +00:00

159 lines
4.3 KiB
JavaScript

import PropTypes from 'prop-types'
import { createElement } from 'react'
import { Flex, Typography, Button, Space, Dropdown, Divider } from 'antd'
import { UserOutlined } from '@ant-design/icons'
import { useContext } from 'react'
import { useNavigate } from 'react-router-dom'
import LogoutIcon from '../../Icons/LogoutIcon'
import { User } from '../../../database/models/User'
import { AuthContext } from '../context/AuthContext'
const { Text } = Typography
const ICON_ACTION_NAMES = ['info', 'edit']
const UserProfilePopover = ({ onClose }) => {
const { userProfile, profileImageUrl, logout } = useContext(AuthContext)
const navigate = useNavigate()
const modelActions = User.actions || []
const iconActions = modelActions.filter((a) => ICON_ACTION_NAMES.includes(a.name))
const dropdownActions = modelActions.filter(
(a) => !ICON_ACTION_NAMES.includes(a.name)
)
const objectData = { ...userProfile, _user: userProfile }
const runAction = (action) => {
if (action.name === 'logout') {
logout()
} else if (action.url && userProfile?._id) {
const url = action.url(userProfile._id)
navigate(url)
}
onClose?.()
}
const isActionDisabled = (action) => {
if (action.disabled && typeof action.disabled === 'function') {
return action.disabled(objectData)
}
return false
}
const username = userProfile?.username
const fullName = [userProfile?.firstName, userProfile?.lastName]
.filter(Boolean)
.join(' ')
const email = userProfile?.email
const dropdownItems = [
...dropdownActions.map((action) => ({
key: action.name,
label: action.label,
icon: action.icon ? createElement(action.icon) : undefined,
disabled: isActionDisabled(action),
onClick: () => !isActionDisabled(action) && runAction(action)
})),
{ type: 'divider' },
{
key: 'logout',
label: 'Logout',
icon: createElement(LogoutIcon),
onClick: () => runAction({ name: 'logout' })
}
]
const actionButton =
dropdownItems.length > 1 ? (
<Dropdown
menu={{ items: dropdownItems }}
trigger={['hover']}
placement='bottomLeft'
>
<Button type='text' size='small' aria-label='Actions'>
Actions
</Button>
</Dropdown>
) : null
return (
<Flex
align='center'
gap='middle'
style={{ minWidth: 240, padding: '0 1px' }}
>
<Flex align='center' gap='12px' style={{ flex: 1, minWidth: 0 }}>
{profileImageUrl ? (
<img
src={profileImageUrl}
alt=''
style={{
width: 76,
height: 76,
borderRadius: '5px',
objectFit: 'cover'
}}
/>
) : (
<UserOutlined
style={{ fontSize: 48, color: 'var(--color-text-secondary)' }}
/>
)}
<Flex vertical style={{ minWidth: 0 }}>
{fullName && (
<Text
strong
ellipsis
style={{ fontSize: 18, lineHeight: 1, marginTop: 1 }}
>
{fullName}
</Text>
)}
{email && (
<Space>
<Text
type='secondary'
strong
style={{ fontSize: 12, lineHeight: 1 }}
>
@{username}
</Text>
<Text
type='secondary'
ellipsis
style={{ fontSize: 12, lineHeight: 1 }}
>
{email}
</Text>
</Space>
)}
{!username && !fullName && !email && (
<Text type='secondary'>Unknown user</Text>
)}
<Divider style={{ margin: '5px 0' }} />
<Flex gap={'1px'}>
{iconActions.map((action) => (
<Button
key={action.name}
type='text'
size='small'
icon={action.icon ? createElement(action.icon) : undefined}
onClick={() => runAction(action)}
aria-label={action.label}
/>
))}
{actionButton}
</Flex>
</Flex>
</Flex>
</Flex>
)
}
UserProfilePopover.propTypes = {
onClose: PropTypes.func
}
export default UserProfilePopover