218 lines
6.3 KiB
JavaScript

// PrinterSelect.js
import PropTypes from 'prop-types'
import { Tree, Card, Spin, Space, Button, message } from 'antd'
import { LoadingOutlined } from '@ant-design/icons'
import React, { useState, useEffect, useContext, useCallback } from 'react'
import { useNavigate } from 'react-router-dom'
import PrinterState from './PrinterState'
import axios from 'axios'
import { PrintServerContext } from '../context/PrintServerContext'
import PrinterIcon from '../../Icons/PrinterIcon'
import SubJobState from './SubJobState'
import SubJobIcon from '../../Icons/SubJobIcon'
import ReloadIcon from '../../Icons/ReloadIcon'
import config from '../../../config'
const SubJobsTree = ({ jobData, loading }) => {
const [treeData, setTreeData] = useState([])
const [treeLoading, setTreeLoading] = useState(loading)
const [error, setError] = useState(null)
const { printServer } = useContext(PrintServerContext)
const [messageApi] = message.useMessage()
const [expandedKeys, setExpandedKeys] = useState([])
const [currentJobData, setCurrentJobData] = useState(null)
const navigate = useNavigate()
const buildTreeData = useCallback(
(jobData) => {
if (!jobData?.subJobs?.length) {
setTreeData([])
setExpandedKeys([])
return
}
// Create tree nodes for each printer
const printerNodes = jobData.printers.map((printerData) => {
// Find subjobs for this printer
const printerSubJobs = jobData.subJobs.filter(
(subJob) => subJob.printer === printerData.id
)
setExpandedKeys((prev) => [...prev, `printer-${printerData.id}`])
return {
title: printerData.state ? (
<Space size={5}>
<PrinterIcon />
<PrinterState
printer={printerData}
text={printerData.name}
showProgress={false}
/>
</Space>
) : (
<Spin indicator={<LoadingOutlined />} />
),
key: `printer-${printerData.id}`,
children: printerSubJobs.map((subJob) => {
return {
title: (
<Space>
<SubJobIcon />
{'Sub Job #' + subJob?.number.toString().padStart(2, '0')}
<SubJobState subJob={subJob} showProgress={true} />
</Space>
),
key: `subjob-${subJob._id}`,
isLeaf: true
}
})
}
})
setTreeData(printerNodes)
},
[expandedKeys]
)
const handleNodeClick = (selectedKeys) => {
const key = selectedKeys[0]
if (key.startsWith('printer-')) {
const printerId = key.replace('printer-', '')
navigate(`/dashboard/production/printers/info?printerId=${printerId}`)
}
}
useEffect(() => {
buildTreeData(currentJobData)
}, [currentJobData])
useEffect(() => {
const initializeData = async () => {
if (!jobData) {
try {
setTreeLoading(true)
const response = await axios.get(`${config.backendUrl}/jobs`, {
headers: { Accept: 'application/json' },
withCredentials: true
})
if (response.data) {
setCurrentJobData(response.data)
}
} catch (err) {
setError('Failed to fetch print job details')
messageApi.error('Failed to fetch print job details')
} finally {
setTreeLoading(false)
}
} else {
setCurrentJobData(jobData)
}
}
initializeData()
// Add printServer.io event listener for deployment updates
if (printServer) {
printServer.on('notify_deployment_update', (updateData) => {
console.log('Received deployment update:', updateData)
setCurrentJobData((prevData) => {
if (!prevData) return prevData
// Handle printer updates
if (updateData.printerId) {
return {
...prevData,
printers: prevData.printers.map((printer) => {
if (
printer.id === updateData.printerId &&
updateData.state == 'deploying'
) {
return {
...printer,
deploymentProgress: updateData.progress
}
} else if (
printer.id === updateData.printerId &&
updateData.state == 'complete'
) {
return {
...printer,
deploymentProgress: undefined
}
}
return printer
})
}
}
return prevData
})
})
printServer.on('notify_subjob_update', (updateData) => {
// Handle sub-job updates
if (updateData.subJobId) {
console.log('Received subjob update:', updateData)
setCurrentJobData((prevData) => {
if (!prevData) return prevData
return {
...prevData,
// eslint-disable-next-line camelcase
subJobs: prevData.subJobs.map((subJob) => {
if (subJob._id === updateData._id) {
return {
...subJob,
state: updateData.state,
subJobId: updateData.subJobId
}
}
return subJob
})
}
})
}
})
}
return () => {
if (printServer) {
printServer.off('notify_deployment_update')
}
}
}, [jobData, printServer])
if (error) {
return (
<Space
direction='vertical'
style={{ width: '100%', textAlign: 'center' }}
>
<p>{error}</p>
<Button icon={<ReloadIcon />} onClick={() => buildTreeData(jobData)}>
Retry
</Button>
</Space>
)
}
return (
<Spin indicator={<LoadingOutlined />} spinning={treeLoading}>
<Card style={{ minHeight: 160 }}>
<Tree
treeData={treeData}
expandedKeys={expandedKeys}
onExpand={setExpandedKeys}
onSelect={handleNodeClick}
showLine={true}
/>
</Card>
</Spin>
)
}
SubJobsTree.propTypes = {
jobData: PropTypes.object.isRequired,
loading: PropTypes.bool
}
export default SubJobsTree