2022-10-25 18:57:23 +05:00
|
|
|
|
import { Breadcrumb, Layout, LayoutProps, Menu, SiderProps } from 'antd'
|
2022-10-13 18:16:43 +05:00
|
|
|
|
import { Key, memo, ReactNode, Suspense, useCallback, useEffect, useMemo, useState } from 'react'
|
2022-10-13 14:31:11 +05:00
|
|
|
|
import { ItemType } from 'antd/lib/menu/hooks/useItems'
|
2022-10-13 18:16:43 +05:00
|
|
|
|
import { Link, Outlet } from 'react-router-dom'
|
2022-10-13 14:31:11 +05:00
|
|
|
|
import {
|
|
|
|
|
ApartmentOutlined,
|
|
|
|
|
CodeOutlined,
|
|
|
|
|
HomeOutlined,
|
|
|
|
|
UserOutlined,
|
|
|
|
|
} from '@ant-design/icons'
|
|
|
|
|
|
2022-10-13 18:16:43 +05:00
|
|
|
|
import { LayoutPropsContext } from '@asb/context'
|
2022-10-13 14:31:11 +05:00
|
|
|
|
import { UserMenu, UserMenuProps } from '@components/UserMenu'
|
|
|
|
|
import { WellTreeSelector, WellTreeSelectorProps } from '@components/selectors/WellTreeSelector'
|
|
|
|
|
import { isURLAvailable, wrapPrivateComponent } from '@utils'
|
|
|
|
|
|
2022-10-13 18:16:43 +05:00
|
|
|
|
import SuspenseFallback from './SuspenseFallback'
|
|
|
|
|
|
2022-10-25 18:57:23 +05:00
|
|
|
|
import Logo from '@images/Logo'
|
|
|
|
|
|
2022-10-13 14:31:11 +05:00
|
|
|
|
import '@styles/layout.less'
|
|
|
|
|
|
|
|
|
|
const { Content, Sider } = Layout
|
|
|
|
|
|
2022-10-21 10:35:13 +05:00
|
|
|
|
export type LayoutPortalProps = Omit<LayoutProps, 'children'> & {
|
2022-10-13 14:31:11 +05:00
|
|
|
|
title?: ReactNode
|
2022-10-13 18:16:43 +05:00
|
|
|
|
sheet?: boolean
|
2022-10-13 14:31:11 +05:00
|
|
|
|
showSelector?: boolean
|
|
|
|
|
selectorProps?: WellTreeSelectorProps
|
|
|
|
|
sider?: boolean | JSX.Element
|
|
|
|
|
siderProps?: SiderProps & { userMenuProps?: UserMenuProps }
|
|
|
|
|
isAdmin?: boolean
|
2022-10-13 18:16:43 +05:00
|
|
|
|
fallback?: JSX.Element
|
2022-10-25 18:57:23 +05:00
|
|
|
|
breadcrumb?: boolean | JSX.Element
|
|
|
|
|
topRightBlock?: JSX.Element
|
2022-10-13 18:16:43 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const defaultProps: LayoutPortalProps = {
|
|
|
|
|
title: 'Единая цифровая платформа',
|
|
|
|
|
sider: true,
|
|
|
|
|
sheet: true,
|
2022-10-13 14:31:11 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const makeItem = (title: string, key: Key, icon: JSX.Element, label?: ReactNode, onClick?: () => void) => ({ icon, key, title, label: label ?? title, onClick })
|
|
|
|
|
|
2022-10-13 18:16:43 +05:00
|
|
|
|
const _LayoutPortal = memo(() => {
|
2022-10-13 14:31:11 +05:00
|
|
|
|
const [menuCollapsed, setMenuCollapsed] = useState<boolean>(true)
|
|
|
|
|
const [wellsTreeOpen, setWellsTreeOpen] = useState<boolean>(false)
|
|
|
|
|
const [userMenuOpen, setUserMenuOpen] = useState<boolean>(false)
|
|
|
|
|
const [currentWell, setCurrentWell] = useState<string>('')
|
2022-10-13 18:16:43 +05:00
|
|
|
|
const [props, setProps] = useState<LayoutPortalProps>(defaultProps)
|
|
|
|
|
|
2022-10-25 18:57:23 +05:00
|
|
|
|
const { isAdmin, title, sheet, showSelector, selectorProps, sider, siderProps, fallback, breadcrumb, topRightBlock, ...other } = useMemo(() => props, [props])
|
2022-10-13 18:16:43 +05:00
|
|
|
|
|
|
|
|
|
const setLayoutProps = useCallback((props: LayoutPortalProps) => setProps({ ...defaultProps, ...props}), [])
|
2022-10-13 14:31:11 +05:00
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (typeof showSelector === 'boolean')
|
|
|
|
|
setWellsTreeOpen(showSelector)
|
|
|
|
|
}, [showSelector])
|
|
|
|
|
|
|
|
|
|
const menuItems = useMemo(() => [
|
|
|
|
|
!isAdmin && makeItem(currentWell, 'well', <ApartmentOutlined/>, null, () => setWellsTreeOpen((prev) => !prev)),
|
|
|
|
|
isAdmin && makeItem('Вернуться на сайт', 'go_back', <HomeOutlined />, <Link to={'/'}>Домой</Link>),
|
|
|
|
|
!isAdmin && isURLAvailable('/admin') && makeItem('Панель администратора', 'admin_panel', <CodeOutlined />, <Link to={'/admin'}>Панель администратора</Link>),
|
|
|
|
|
makeItem('Профиль', 'profile', <UserOutlined/>, null, () => setUserMenuOpen((prev) => !prev)),
|
|
|
|
|
].filter(Boolean) as ItemType[], [isAdmin, currentWell])
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Layout className={`page-layout ${isAdmin ? 'page-layout-admin' : ''}`}>
|
|
|
|
|
{(sider || siderProps) && (
|
2022-10-21 10:35:13 +05:00
|
|
|
|
<Sider {...siderProps} collapsedWidth={50} collapsed={menuCollapsed} trigger={null} collapsible className={`menu-sider ${siderProps?.className || ''}`}>
|
2022-10-13 14:31:11 +05:00
|
|
|
|
<div className={'sider-content'}>
|
|
|
|
|
<button className={'sider-toogle'} onClick={() => setMenuCollapsed((prev) => !prev)}>
|
2022-10-25 18:57:23 +05:00
|
|
|
|
<Logo onlyIcon={menuCollapsed} />
|
2022-10-13 14:31:11 +05:00
|
|
|
|
</button>
|
|
|
|
|
<div className={'scrollable hide-slider'}>
|
|
|
|
|
{sider}
|
|
|
|
|
</div>
|
|
|
|
|
<Menu
|
|
|
|
|
mode={'inline'}
|
|
|
|
|
items={menuItems}
|
|
|
|
|
theme={'dark'}
|
|
|
|
|
selectable={false}
|
|
|
|
|
/>
|
|
|
|
|
<UserMenu
|
|
|
|
|
open={userMenuOpen}
|
|
|
|
|
onClose={() => setUserMenuOpen(false)}
|
|
|
|
|
isAdmin={isAdmin}
|
|
|
|
|
{...siderProps?.userMenuProps}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Sider>
|
|
|
|
|
)}
|
2022-10-25 18:57:23 +05:00
|
|
|
|
{!isAdmin && (
|
|
|
|
|
<WellTreeSelector
|
|
|
|
|
open={wellsTreeOpen}
|
|
|
|
|
onClose={() => setWellsTreeOpen(false)}
|
|
|
|
|
{...selectorProps}
|
|
|
|
|
onChange={(well) => setCurrentWell(well ?? 'Выберите месторождение')}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2022-10-13 14:31:11 +05:00
|
|
|
|
<Layout className={'page-content'}>
|
2022-10-13 18:16:43 +05:00
|
|
|
|
<Content {...other} className={`${sheet ? 'site-layout-background sheet' : ''} ${other.className ?? ''}`}>
|
2022-10-25 18:57:23 +05:00
|
|
|
|
{(breadcrumb || topRightBlock) && (
|
|
|
|
|
<div className={'breadcrumb-block'}>
|
|
|
|
|
{breadcrumb && (
|
|
|
|
|
<Breadcrumb>
|
|
|
|
|
<Breadcrumb.Item href={'/'}>
|
|
|
|
|
<HomeOutlined />
|
|
|
|
|
</Breadcrumb.Item>
|
|
|
|
|
{!isAdmin && (
|
|
|
|
|
<Breadcrumb.Item>
|
|
|
|
|
<a style={{ userSelect: 'none' }} onClick={() => setWellsTreeOpen((prev) => !prev)}>{currentWell}</a>
|
|
|
|
|
</Breadcrumb.Item>
|
|
|
|
|
)}
|
|
|
|
|
{breadcrumb}
|
|
|
|
|
</Breadcrumb>
|
|
|
|
|
)}
|
|
|
|
|
{topRightBlock}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2022-10-13 18:16:43 +05:00
|
|
|
|
<LayoutPropsContext.Provider value={setLayoutProps}>
|
|
|
|
|
<Suspense fallback={fallback ?? <SuspenseFallback style={{ minHeight: '100%' }} />}>
|
|
|
|
|
<Outlet />
|
|
|
|
|
</Suspense>
|
|
|
|
|
</LayoutPropsContext.Provider>
|
2022-10-13 14:31:11 +05:00
|
|
|
|
</Content>
|
|
|
|
|
</Layout>
|
|
|
|
|
</Layout>
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
|
2022-10-25 18:57:23 +05:00
|
|
|
|
export const LayoutPortal = wrapPrivateComponent(_LayoutPortal, { requirements: ['Deposit.get'] })
|
2022-10-13 14:31:11 +05:00
|
|
|
|
|
|
|
|
|
export default LayoutPortal
|