2025-08-22 20:28:50 +01:00

261 lines
7.9 KiB
JavaScript

import { useState, useContext, useEffect } from 'react'
import { Form, Button, Typography, Flex, Steps, Divider, Alert } from 'antd'
import { useMediaQuery } from 'react-responsive'
import PropTypes from 'prop-types'
import { PrintServerContext } from '../../context/PrintServerContext'
import PrinterSelect from '../../common/PrinterSelect'
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
import { LoadingOutlined } from '@ant-design/icons'
const { Title } = Typography
const UnloadFilamentStock = ({ onOk, reset, printer = null }) => {
UnloadFilamentStock.propTypes = {
onOk: PropTypes.func.isRequired,
reset: PropTypes.bool.isRequired,
printer: PropTypes.object
}
const { printServer } = useContext(PrintServerContext)
const isMobile = useMediaQuery({ maxWidth: 768 })
const initialUnloadFilamentStockForm = {
printer: printer
}
const [unloadFilamentStockLoading, setUnloadFilamentStockLoading] =
useState(false)
const [currentStep, setCurrentStep] = useState(0)
const [nextEnabled, setNextEnabled] = useState(false)
const [currentTemperature, setCurrentTemperature] = useState(-1)
const [targetTemperature, setTargetTemperature] = useState(0)
const [filamentSensorDetected, setFilamentSensorDetected] = useState(true)
const [unloadFilamentStockForm] = Form.useForm()
const [unloadFilamentStockFormValues, setUnloadFilamentStockFormValues] =
useState(initialUnloadFilamentStockForm)
// Add websocket temperature monitoring
useEffect(() => {
if (unloadFilamentStockFormValues.printer) {
const params = {
printerId: unloadFilamentStockFormValues.printer._id,
objects: {
extruder: null,
'filament_switch_sensor fsensor': null
}
}
const notifyStatusUpdate = (statusUpdate) => {
if (statusUpdate?.extruder?.temperature !== undefined) {
setCurrentTemperature(statusUpdate.extruder.temperature)
}
if (statusUpdate?.extruder?.target !== undefined) {
setTargetTemperature(statusUpdate.extruder.target)
}
if (
statusUpdate?.['filament_switch_sensor fsensor']
?.filament_detected !== undefined
) {
setFilamentSensorDetected(
Boolean(
statusUpdate['filament_switch_sensor fsensor'].filament_detected
)
)
}
}
printServer.emit('printer.objects.subscribe', params)
printServer.emit('printer.objects.query', params)
printServer.on('notify_status_update', notifyStatusUpdate)
return () => {
printServer.off('notify_status_update', notifyStatusUpdate)
printServer.emit('printer.objects.unsubscribe', params)
}
}
}, [printServer, unloadFilamentStockFormValues.printer])
useEffect(() => {
if (reset) {
unloadFilamentStockForm.resetFields()
}
}, [reset, unloadFilamentStockForm])
useEffect(() => {
unloadFilamentStockForm
.validateFields({
validateOnly: true
})
.then(() => {
// Only enable next if we have a printer selected, we're not loading, and we've reached target temperature
setNextEnabled(
Boolean(unloadFilamentStockFormValues.printer) &&
!unloadFilamentStockLoading &&
currentTemperature + 1 > targetTemperature &&
targetTemperature != 0
)
})
.catch(() => setNextEnabled(false))
}, [
unloadFilamentStockForm,
unloadFilamentStockFormValues,
unloadFilamentStockLoading,
currentTemperature,
targetTemperature
])
const handleUnloadFilamentStock = async () => {
setUnloadFilamentStockLoading(true)
// Send G-code to retract the filament
await printServer.emit('printer.gcode.script', {
printerId: unloadFilamentStockFormValues.printer._id,
script: `_CLIENT_LINEAR_MOVE E=-200 F=1000`
})
//setUnloadFilamentStockLoading(false)
}
useEffect(() => {
if (unloadFilamentStockLoading == true && filamentSensorDetected == false) {
setUnloadFilamentStockLoading(false)
onOk()
}
}, [unloadFilamentStockLoading, filamentSensorDetected, onOk])
const steps = [
{
title: 'Preheat',
key: 'preHeat',
content: (
<Flex vertical gap={'middle'} style={{ paddingBottom: 16 }}>
<Form.Item
label='Printer'
name='printer'
style={{ margin: 0 }}
rules={[
{
required: true,
message: 'Please select a printer'
}
]}
>
<PrinterSelect checkable={false} />
</Form.Item>
{unloadFilamentStockLoading == false ? (
<>
{targetTemperature == 0 ? (
<Alert
message={'Heat the extruder to start unloading filament.'}
type='info'
showIcon
/>
) : null}
{targetTemperature > 0 &&
currentTemperature < targetTemperature ? (
<Alert
message={'Heating extruder...'}
type='error'
showIcon
icon={<LoadingOutlined />}
/>
) : null}
{targetTemperature > 0 &&
currentTemperature + 1 > targetTemperature &&
filamentSensorDetected ? (
<Alert
message={'Ready to unload filament stock.'}
type='success'
showIcon
/>
) : null}
</>
) : (
<Alert
message={'Unloading filament stock...'}
type='info'
showIcon
icon={<LoadingOutlined />}
/>
)}
{unloadFilamentStockFormValues.printer ? (
<PrinterTemperaturePanel
showHeatedBed={false}
showMoreInfo={false}
printerId={unloadFilamentStockFormValues.printer._id}
/>
) : null}
</Flex>
)
}
]
return (
<Flex gap={'middle'}>
{!isMobile && (
<div style={{ minWidth: '160px' }}>
<Steps
current={currentStep}
items={steps}
direction='vertical'
style={{ width: 'fit-content' }}
/>
</div>
)}
{!isMobile && <Divider type={'vertical'} style={{ height: 'unset' }} />}
<Flex vertical={'true'} style={{ flexGrow: 1 }} gap='middle'>
<Title level={2} style={{ marginTop: 0, marginBottom: 4 }}>
Unload Filament Stock
</Title>
<Form
name='unloadFilamentStock'
autoComplete='off'
form={unloadFilamentStockForm}
onFinish={handleUnloadFilamentStock}
onValuesChange={(changedValues) =>
setUnloadFilamentStockFormValues((prevValues) => ({
...prevValues,
...changedValues
}))
}
initialValues={initialUnloadFilamentStockForm}
>
<div style={{ minHeight: '260px' }}>{steps[currentStep].content}</div>
<Flex justify={'end'}>
<Button
style={{
margin: '0 8px'
}}
onClick={() => setCurrentStep(currentStep - 1)}
disabled={!(currentStep > 0)}
>
Previous
</Button>
{currentStep === steps.length - 1 && (
<Button
type='primary'
loading={unloadFilamentStockLoading}
disabled={!nextEnabled}
onClick={() => {
unloadFilamentStockForm.submit()
}}
>
{unloadFilamentStockLoading ? 'Unloading...' : 'Unload'}
</Button>
)}
</Flex>
</Form>
</Flex>
</Flex>
)
}
export default UnloadFilamentStock