214 lines
5.4 KiB
JavaScript
214 lines
5.4 KiB
JavaScript
// FilamentSelect.js
|
|
import { TreeSelect, Badge } from 'antd'
|
|
import React, { useEffect, useState, useCallback } from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import axios from 'axios'
|
|
|
|
import config from '../../../config'
|
|
|
|
const propertyOrder = ['diameter', 'type', 'vendor.name']
|
|
|
|
const FilamentSelect = ({ onChange, filter, useFilter, value }) => {
|
|
const [filamentsTreeData, setFilamentsTreeData] = useState([])
|
|
const [filamentsData, setFilamentsData] = useState([])
|
|
const [loading, setLoading] = useState(false)
|
|
const [defaultValue, setDefaultValue] = useState(value)
|
|
|
|
const fetchFilamentsData = async (property, filter) => {
|
|
setLoading(true)
|
|
try {
|
|
const response = await axios.get(`${config.backendUrl}/filaments`, {
|
|
params: {
|
|
...filter,
|
|
property
|
|
},
|
|
headers: {
|
|
Accept: 'application/json'
|
|
},
|
|
withCredentials: true
|
|
})
|
|
setLoading(false)
|
|
return response.data
|
|
//setPagination({ ...pagination, total: response.data.totalItems }); // Update total count
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
}
|
|
|
|
function getByPath(obj, path) {
|
|
return path.split('.').reduce((acc, part) => acc && acc[part], obj)
|
|
}
|
|
|
|
const getFilter = useCallback(
|
|
(node) => {
|
|
var filter = {}
|
|
var currentId = node.id
|
|
while (currentId != 0) {
|
|
const currentNode = filamentsTreeData.filter(
|
|
(treeData) => treeData['id'] === currentId
|
|
)[0]
|
|
filter[propertyOrder[currentNode.propertyId]] = currentNode.value
|
|
currentId = currentNode.pId
|
|
}
|
|
return filter
|
|
},
|
|
[filamentsTreeData]
|
|
)
|
|
|
|
const generateFilamentTreeNodes = useCallback(
|
|
async (node = null, filter = null) => {
|
|
if (!node) {
|
|
return
|
|
}
|
|
|
|
if (filter === null) {
|
|
filter = getFilter(node)
|
|
}
|
|
|
|
const filamentData = await fetchFilamentsData(null, filter)
|
|
|
|
setFilamentsData(filamentData)
|
|
|
|
for (var i = 0; i < filamentData.length; i++) {
|
|
const filament = filamentData[i]
|
|
|
|
const newNode = {
|
|
id: filament._id,
|
|
pId: node.id,
|
|
value: filament._id,
|
|
key: filament._id,
|
|
title: <Badge color={filament.color} text={filament.name} />,
|
|
isLeaf: true
|
|
}
|
|
|
|
setFilamentsTreeData((prev) => {
|
|
const filtered = prev.filter((node) => node.id !== newNode.id)
|
|
return [...filtered, newNode]
|
|
})
|
|
}
|
|
},
|
|
[filamentsTreeData, getFilter]
|
|
)
|
|
|
|
const generateFilamentCategoryTreeNodes = useCallback(
|
|
async (node = null) => {
|
|
var filter = {}
|
|
|
|
var propertyId = 0
|
|
|
|
if (!node) {
|
|
node = {}
|
|
node.id = 0
|
|
} else {
|
|
filter = getFilter(node)
|
|
propertyId = node.propertyId + 1
|
|
}
|
|
|
|
const propertyName = propertyOrder[propertyId]
|
|
|
|
const propertyData = await fetchFilamentsData(propertyName, filter)
|
|
|
|
for (var i = 0; i < propertyData.length; i++) {
|
|
const property = getByPath(propertyData[i], propertyName)
|
|
const newNode = {
|
|
id: property,
|
|
pId: node.id,
|
|
value: property,
|
|
key: property,
|
|
propertyId: propertyId,
|
|
title: property,
|
|
isLeaf: false,
|
|
selectable: false
|
|
}
|
|
|
|
setFilamentsTreeData((prev) => {
|
|
if (prev.some((node) => node.id === newNode.id)) {
|
|
return prev // already added
|
|
}
|
|
return [...prev, newNode]
|
|
})
|
|
}
|
|
},
|
|
[getFilter]
|
|
)
|
|
|
|
const handleFilamentsTreeLoad = useCallback(
|
|
async (node) => {
|
|
if (node) {
|
|
if (node.propertyId !== propertyOrder.length - 1) {
|
|
await generateFilamentCategoryTreeNodes(node)
|
|
} else {
|
|
await generateFilamentTreeNodes(node) // End of properties
|
|
}
|
|
} else {
|
|
await generateFilamentCategoryTreeNodes(null) // First property
|
|
}
|
|
},
|
|
[generateFilamentTreeNodes, generateFilamentCategoryTreeNodes]
|
|
)
|
|
|
|
const handleOnChange = (value, selectedOptions) => {
|
|
console.log('Handle onchange')
|
|
const filamentObject = filamentsData.filter(
|
|
(filament) => filament._id == value
|
|
)[0]
|
|
|
|
onChange(filamentObject, selectedOptions)
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (value?._id != null) {
|
|
console.log('Setting default value...', value)
|
|
setDefaultValue(value)
|
|
}
|
|
}, [value])
|
|
|
|
useEffect(() => {
|
|
console.log('Use Filter', useFilter)
|
|
if (defaultValue != undefined) {
|
|
const newNode = {
|
|
id: defaultValue._id,
|
|
pId: 0,
|
|
value: defaultValue._id,
|
|
key: defaultValue._id,
|
|
title: <Badge color={defaultValue.color} text={defaultValue.name} />,
|
|
isLeaf: true
|
|
}
|
|
console.log('setting new node')
|
|
setFilamentsTreeData([newNode])
|
|
} else {
|
|
setFilamentsTreeData([])
|
|
}
|
|
if (useFilter === true) {
|
|
generateFilamentTreeNodes({ id: 0 }, filter)
|
|
} else {
|
|
handleFilamentsTreeLoad(null)
|
|
}
|
|
}, [useFilter, defaultValue, filter])
|
|
|
|
return (
|
|
<TreeSelect
|
|
treeDataSimpleMode
|
|
value={defaultValue?._id}
|
|
loadData={handleFilamentsTreeLoad}
|
|
treeData={filamentsTreeData}
|
|
onChange={handleOnChange}
|
|
loading={loading}
|
|
/>
|
|
)
|
|
}
|
|
|
|
FilamentSelect.propTypes = {
|
|
onChange: PropTypes.func.isRequired,
|
|
value: PropTypes.object,
|
|
filter: PropTypes.object,
|
|
useFilter: PropTypes.bool
|
|
}
|
|
|
|
FilamentSelect.defaultProps = {
|
|
filter: {},
|
|
useFilter: false
|
|
}
|
|
|
|
export default FilamentSelect
|