- Introduced new SVG icons for client and sales order. - Implemented SalesRoutes for navigation. - Created components for managing clients and sales orders, including overview, client info, and order details. - Added functionality for creating, editing, and canceling sales orders. - Integrated sales statistics and actions within the dashboard layout.
372 lines
11 KiB
JavaScript
372 lines
11 KiB
JavaScript
// DashboardNavigation.js
|
|
import { useContext, useEffect, useState, useMemo } from 'react'
|
|
import {
|
|
Menu,
|
|
Flex,
|
|
Tag,
|
|
Space,
|
|
Dropdown,
|
|
Button,
|
|
Tooltip,
|
|
Badge,
|
|
Divider,
|
|
Typography
|
|
} from 'antd'
|
|
import {
|
|
LogoutOutlined,
|
|
MailOutlined,
|
|
LoadingOutlined
|
|
} from '@ant-design/icons'
|
|
import { AuthContext } from '../context/AuthContext'
|
|
import { SpotlightContext } from '../context/SpotlightContext'
|
|
import { ApiServerContext } from '../context/ApiServerContext'
|
|
import { useNavigate, useLocation } from 'react-router-dom'
|
|
import { Header } from 'antd/es/layout/layout'
|
|
import { useMediaQuery } from 'react-responsive'
|
|
import KeyboardShortcut from './KeyboardShortcut'
|
|
|
|
import FarmControlLogo from '../../Logos/FarmControlLogo'
|
|
import FarmControlLogoSmall from '../../Logos/FarmControlLogoSmall'
|
|
import MenuIcon from '../../Icons/MenuIcon'
|
|
import ProductionIcon from '../../Icons/ProductionIcon'
|
|
import InventoryIcon from '../../Icons/InventoryIcon'
|
|
import FinanceIcon from '../../Icons/FinanceIcon'
|
|
import SalesIcon from '../../Icons/SalesIcon'
|
|
import PersonIcon from '../../Icons/PersonIcon'
|
|
import CloudIcon from '../../Icons/CloudIcon'
|
|
import BellIcon from '../../Icons/BellIcon'
|
|
import SearchIcon from '../../Icons/SearchIcon'
|
|
import SettingsIcon from '../../Icons/SettingsIcon'
|
|
import DeveloperIcon from '../../Icons/DeveloperIcon'
|
|
import { ElectronContext } from '../context/ElectronContext'
|
|
import DashboardWindowButtons from './DashboardWindowButtons'
|
|
|
|
const { Text } = Typography
|
|
|
|
const DashboardNavigation = () => {
|
|
const { logout, userProfile } = useContext(AuthContext)
|
|
const { showSpotlight } = useContext(SpotlightContext)
|
|
const { toggleNotificationCenter, unreadCount } = useContext(ApiServerContext)
|
|
const { connecting, connected } = useContext(ApiServerContext)
|
|
const [apiServerState, setApiServerState] = useState('disconnected')
|
|
const navigate = useNavigate()
|
|
const location = useLocation()
|
|
const [selectedKey, setSelectedKey] = useState('production')
|
|
const [selectedMenuItem, setSelectedMenuItem] = useState({
|
|
key: 'production',
|
|
label: 'Production',
|
|
icon: <ProductionIcon />
|
|
})
|
|
const isMobile = useMediaQuery({ maxWidth: 768 })
|
|
const { platform, isElectron, isFullScreen } = useContext(ElectronContext)
|
|
|
|
const mainMenuItems = useMemo(
|
|
() => [
|
|
{
|
|
key: 'production',
|
|
label: 'Production',
|
|
icon: <ProductionIcon />
|
|
},
|
|
{
|
|
key: 'inventory',
|
|
label: 'Inventory',
|
|
icon: <InventoryIcon />
|
|
},
|
|
{
|
|
key: 'sales',
|
|
label: 'Sales',
|
|
icon: <SalesIcon />
|
|
},
|
|
{
|
|
key: 'finance',
|
|
label: 'Finance',
|
|
icon: <FinanceIcon />
|
|
},
|
|
{
|
|
key: 'management',
|
|
label: 'Management',
|
|
icon: <SettingsIcon />
|
|
}
|
|
],
|
|
[]
|
|
)
|
|
|
|
const userMenuItems = {
|
|
items: [
|
|
{
|
|
key: 'username',
|
|
label: userProfile?.username,
|
|
icon: <PersonIcon />,
|
|
disabled: true
|
|
},
|
|
{
|
|
key: 'email',
|
|
label: userProfile?.email,
|
|
icon: <MailOutlined />,
|
|
disabled: true
|
|
},
|
|
{
|
|
key: 'logout',
|
|
label: 'Logout',
|
|
icon: <LogoutOutlined />
|
|
}
|
|
],
|
|
onClick: (key) => {
|
|
if (key === 'profile') {
|
|
navigate('/profile')
|
|
} else if (key === 'logout') {
|
|
logout()
|
|
}
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
const pathParts = location.pathname.split('/').filter(Boolean)
|
|
if (pathParts.length > 2) {
|
|
setSelectedMenuItem(
|
|
mainMenuItems.filter((item) => item.key == pathParts[1])[0]
|
|
)
|
|
setSelectedKey(pathParts[1]) // Return the section (production/management)
|
|
}
|
|
}, [location.pathname, mainMenuItems])
|
|
|
|
useEffect(() => {
|
|
if (connecting == true) {
|
|
setApiServerState('connecting')
|
|
} else if (connected == true) {
|
|
setApiServerState('connected')
|
|
} else {
|
|
setApiServerState('disconnected')
|
|
}
|
|
}, [connecting, connected])
|
|
|
|
const handleMainMenuClick = ({ key }) => {
|
|
if (key === 'production') {
|
|
navigate('/dashboard/production/overview')
|
|
} else if (key === 'inventory') {
|
|
navigate('/dashboard/inventory/overview')
|
|
} else if (key === 'finance') {
|
|
navigate('/dashboard/finance/overview')
|
|
} else if (key === 'sales') {
|
|
navigate('/dashboard/sales/overview')
|
|
} else if (key === 'management') {
|
|
navigate('/dashboard/management/filaments')
|
|
}
|
|
}
|
|
|
|
const showAppLogo =
|
|
(isElectron && platform == 'darwin' && isFullScreen == true) ||
|
|
(isElectron && platform != 'darwin')
|
|
const isMacOSApp = isElectron && platform == 'darwin'
|
|
const isOtherApp = isElectron && platform != 'darwin'
|
|
|
|
const showDesktopLogo = !isElectron && !isMobile
|
|
const showMobileLogo = !isElectron && isMobile
|
|
|
|
const navigationContents = (
|
|
<Flex style={{ width: '100%' }} align='center'>
|
|
{isMacOSApp ? <DashboardWindowButtons /> : null}
|
|
{showAppLogo == true && (
|
|
<FarmControlLogoSmall
|
|
style={{
|
|
fontSize: '46px',
|
|
height: '16px',
|
|
marginLeft: '15px',
|
|
marginRight: '8px'
|
|
}}
|
|
/>
|
|
)}
|
|
{showDesktopLogo == true ? (
|
|
<FarmControlLogo
|
|
style={{
|
|
fontSize: '200px',
|
|
height: '18px',
|
|
marginRight: '15px'
|
|
}}
|
|
/>
|
|
) : showMobileLogo == true ? (
|
|
<FarmControlLogoSmall
|
|
style={{
|
|
fontSize: '48px',
|
|
marginRight: isElectron ? '20px' : '25px'
|
|
}}
|
|
/>
|
|
) : null}
|
|
{isMobile && (
|
|
<Flex
|
|
gap={'small'}
|
|
align='center'
|
|
style={{
|
|
marginLeft: '16px',
|
|
minWidth: 0, // allow children to shrink
|
|
maxWidth: '100%' // responsive
|
|
}}
|
|
>
|
|
{selectedMenuItem.icon}
|
|
<Text
|
|
ellipsis
|
|
style={{
|
|
minWidth: 0, // CRUCIAL for flex children
|
|
maxWidth: '100%', // Responsive
|
|
whiteSpace: 'nowrap',
|
|
overflow: 'hidden',
|
|
textOverflow: 'ellipsis',
|
|
flex: 1 // Take available space, shrink as needed
|
|
}}
|
|
>
|
|
{selectedMenuItem.label}
|
|
</Text>
|
|
</Flex>
|
|
)}
|
|
<Menu
|
|
mode='horizontal'
|
|
className={isElectron ? 'electron-navigation' : null}
|
|
items={mainMenuItems}
|
|
style={{
|
|
flexWrap: 'wrap',
|
|
flexGrow: isMobile ? 0 : 1,
|
|
border: 0,
|
|
width: isMobile ? '64px' : 'unset'
|
|
}}
|
|
onClick={handleMainMenuClick}
|
|
selectedKeys={[selectedKey]}
|
|
overflowedIndicator={
|
|
<Button
|
|
type='text'
|
|
icon={<MenuIcon />}
|
|
style={{ marginBottom: '4px' }}
|
|
/>
|
|
}
|
|
/>
|
|
{isMobile && <div style={{ flexGrow: 1 }} />}
|
|
<Flex
|
|
gap={'small'}
|
|
align='center'
|
|
style={{ marginTop: '-2px', marginRight: '6px' }}
|
|
>
|
|
<Space>
|
|
<KeyboardShortcut
|
|
shortcut='alt+q'
|
|
hint='ALT Q'
|
|
onTrigger={() => showSpotlight()}
|
|
>
|
|
<Button
|
|
icon={<SearchIcon />}
|
|
type='text'
|
|
style={{ marginTop: '2px' }}
|
|
onClick={() => showSpotlight()}
|
|
/>
|
|
</KeyboardShortcut>
|
|
<Badge count={unreadCount} size='small'>
|
|
<KeyboardShortcut
|
|
shortcut='alt+n'
|
|
hint='ALT N'
|
|
onTrigger={() => toggleNotificationCenter()}
|
|
>
|
|
<Button
|
|
icon={<BellIcon />}
|
|
type='text'
|
|
style={{ marginTop: '2px' }}
|
|
onClick={() => toggleNotificationCenter()}
|
|
/>
|
|
</KeyboardShortcut>
|
|
</Badge>
|
|
</Space>
|
|
{import.meta.env.MODE === 'development' && (
|
|
<Space>
|
|
{apiServerState === 'connected' ? (
|
|
<Tooltip title='Connected to api server' arrow={false}>
|
|
<Tag
|
|
color='success'
|
|
style={{ marginRight: 0 }}
|
|
icon={<CloudIcon />}
|
|
/>
|
|
</Tooltip>
|
|
) : null}
|
|
{apiServerState === 'connecting' ? (
|
|
<Tooltip title='Connecting to api erver...' arrow={false}>
|
|
<Tag
|
|
color='warning'
|
|
style={{ marginRight: 0 }}
|
|
icon={<LoadingOutlined />}
|
|
/>
|
|
</Tooltip>
|
|
) : null}
|
|
{apiServerState === 'disconnected' ? (
|
|
<Tooltip title='Disconnected from api server' arrow={false}>
|
|
<Tag
|
|
color='error'
|
|
style={{ marginRight: 0 }}
|
|
icon={<CloudIcon />}
|
|
/>
|
|
</Tooltip>
|
|
) : null}
|
|
<Tooltip title='Developer' arrow={false}>
|
|
<Tag
|
|
color='yellow'
|
|
style={{ marginRight: 0 }}
|
|
icon={<DeveloperIcon />}
|
|
onClick={() => {
|
|
navigate('/dashboard/developer/sessionstorage')
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
</Space>
|
|
)}
|
|
{userProfile ? (
|
|
<Space>
|
|
<Dropdown menu={userMenuItems} placement='bottomRight'>
|
|
<Tag style={{ marginRight: 0 }} icon={<PersonIcon />}>
|
|
{!isMobile && (userProfile?.name || userProfile.username)}
|
|
</Tag>
|
|
</Dropdown>
|
|
</Space>
|
|
) : null}
|
|
</Flex>
|
|
{isOtherApp ? <DashboardWindowButtons /> : null}
|
|
</Flex>
|
|
)
|
|
|
|
return (
|
|
<>
|
|
{isElectron ? (
|
|
<Flex
|
|
className='ant-menu-horizontal ant-menu-light electron-navigation-wrapper'
|
|
style={{ lineHeight: '40px', padding: '0 2px 0 2px' }}
|
|
>
|
|
{navigationContents}
|
|
</Flex>
|
|
) : (
|
|
<Flex vertical>
|
|
<Header
|
|
style={{
|
|
width: '100vw',
|
|
padding: 0,
|
|
marginBottom: '0.1px',
|
|
background: 'unset'
|
|
}}
|
|
theme='light'
|
|
className='ant-menu-horizontal'
|
|
>
|
|
<Flex
|
|
gap={'large'}
|
|
align='center'
|
|
className='ant-menu-light'
|
|
style={{
|
|
padding: '0 26px',
|
|
height: '100%',
|
|
borderBottom: '1px solid rgba(5, 5, 5, 0.00)'
|
|
}}
|
|
>
|
|
{navigationContents}
|
|
</Flex>
|
|
<Divider style={{ margin: 0 }} />
|
|
</Header>
|
|
</Flex>
|
|
)}
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default DashboardNavigation
|