asb_cloud_front/src/components/selectors/WellTreeSelector.tsx

139 lines
5.6 KiB
TypeScript
Raw Normal View History

import { TreeSelect } from 'antd'
import { LabelInValueType } from 'rc-select/lib/Select'
import { RawValueType } from 'rc-tree-select/lib/TreeSelect'
import { DefaultValueType } from 'rc-tree-select/lib/interface'
import { useState, useEffect, ReactNode, useCallback, memo } from 'react'
import { useNavigate, useLocation } from 'react-router-dom'
import { isRawDate } from '@utils'
import LoaderPortal from '@components/LoaderPortal'
import { WellIcon, WellIconState } from '@components/icons'
import { invokeWebApiWrapperAsync } from '@components/factory'
import { DepositService, DepositDto } from '@api'
import { ReactComponent as DepositIcon } from '@images/DepositIcon.svg'
import { ReactComponent as ClusterIcon } from '@images/ClusterIcon.svg'
import '@styles/wellTreeSelect.css'
export const getWellState = (idState?: number): WellIconState => idState === 1 ? 'active' : 'unknown'
export const checkIsWellOnline = (lastTelemetryDate: unknown): boolean =>
isRawDate(lastTelemetryDate) && (Date.now() - +new Date(lastTelemetryDate) < 600_000)
export type TreeNodeData = {
title?: string | null
key?: string
value?: DefaultValueType
icon?: ReactNode
children?: TreeNodeData[]
}
const getLabel = (wellsTree: TreeNodeData[], value?: string): string | undefined => {
const result = value?.match(/^\/([^\/]+)\/([^\/?]+)/) // pattern "/:type/:id"
if (wellsTree.length <= 0 || !result) return
const [url, type] = result
let deposit: TreeNodeData | undefined
let cluster: TreeNodeData | undefined
let well: TreeNodeData | undefined
switch (type) {
case 'deposit':
deposit = wellsTree.find((deposit) => deposit.key === url)
if (deposit)
return `${deposit.title}`
return 'Ошибка! Месторождение не найдено!'
case 'cluster':
deposit = wellsTree.find((deposit) => (
cluster = deposit.children?.find((cluster: TreeNodeData) => cluster.key === url)
))
if (deposit && cluster)
return `${deposit.title} / ${cluster.title}`
return 'Ошибка! Куст не найден!'
case 'well':
deposit = wellsTree.find((deposit) => (
cluster = deposit.children?.find((cluster: TreeNodeData) => (
well = cluster.children?.find((well: TreeNodeData) => well.key === url)
))
))
if (deposit && cluster && well)
return `${deposit.title} / ${cluster.title} / ${well.title}`
return 'Ошибка! Скважина не найдена!'
default: break
}
}
export const WellTreeSelector = memo(({ ...other }) => {
const [wellsTree, setWellsTree] = useState<TreeNodeData[]>([])
const [showLoader, setShowLoader] = useState<boolean>(false)
const [value, setValue] = useState<string>()
const navigate = useNavigate()
const location = useLocation()
useEffect(() => {
invokeWebApiWrapperAsync(
async () => {
const deposits: Array<DepositDto> = await DepositService.getDeposits()
const wellsTree: TreeNodeData[] = deposits.map(deposit =>({
title: deposit.caption,
key: `/deposit/${deposit.id}`,
value: `/deposit/${deposit.id}`,
icon: <DepositIcon width={24} height={24}/>,
children: deposit.clusters?.map(cluster => ({
title: cluster.caption,
key: `/cluster/${cluster.id}`,
value: `/cluster/${cluster.id}`,
icon: <ClusterIcon width={24} height={24}/>,
children: cluster.wells?.map(well => ({
title: well.caption,
key: `/well/${well.id}`,
value: `/well/${well.id}`,
icon: <WellIcon
width={24}
height={24}
state={getWellState(well.idState)}
online={checkIsWellOnline(well.lastTelemetryDate)}
/>
})),
})),
}))
setWellsTree(wellsTree)
},
setShowLoader,
`Не удалось загрузить список скважин`,
'Получить список скважин'
)
}, [])
useEffect(() => setValue(getLabel(wellsTree, location.pathname)), [wellsTree, location])
const onChange = useCallback((value?: string): void => setValue(getLabel(wellsTree, value)), [wellsTree])
const onSelect = useCallback((value: RawValueType | LabelInValueType): void => {
if (['number', 'string'].includes(typeof value))
navigate(String(value), { state: { from: location.pathname }})
}, [navigate, location])
return (
<LoaderPortal show={showLoader}>
<TreeSelect
treeIcon
className={'header-tree-select'}
bordered={false}
dropdownMatchSelectWidth={false}
placeholder={'Выберите месторождение'}
treeData={wellsTree}
treeDefaultExpandAll
onSelect={onSelect}
onChange={onChange}
value={value}
style={{ width: '350px' }}
{...other}
/>
</LoaderPortal>
)
})
export default WellTreeSelector