282 lines
7.7 KiB
JavaScript

import { useState, useContext, useEffect } from 'react'
import { Form, Flex, Descriptions, Alert } from 'antd'
import PropTypes from 'prop-types'
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
import { LoadingOutlined } from '@ant-design/icons'
import ObjectSelect from '../../common/ObjectSelect'
import ObjectDisplay from '../../common/ObjectDisplay'
import WizardView from '../../common/WizardView'
import { ApiServerContext } from '../../context/ApiServerContext'
const LoadFilamentStock = ({
onOk,
reset,
printer = null,
filamentStockLoaded = false
}) => {
const { connected, subscribeToObjectEvent, sendObjectAction } =
useContext(ApiServerContext)
LoadFilamentStock.propTypes = {
onOk: PropTypes.func.isRequired,
reset: PropTypes.bool.isRequired,
printer: PropTypes.object,
filamentStockLoaded: PropTypes.bool
}
const initialLoadFilamentStockForm = {
printer: printer,
filamentStock: null
}
const [loadFilamentStockLoading, setLoadFilamentStockLoading] =
useState(false)
const [formValid, setFormValid] = useState(false)
const [currentTemperature, setCurrentTemperature] = useState(-1)
const [targetTemperature, setTargetTemperature] = useState(0)
const [filamentSensorDetected, setFilamentSensorDetected] =
useState(filamentStockLoaded)
const [loadFilamentStockForm] = Form.useForm()
const [loadFilamentStockFormValues, setLoadFilamentStockFormValues] =
useState(initialLoadFilamentStockForm)
const loadFilamentStockFormUpdateValues = Form.useWatch(
[],
loadFilamentStockForm
)
useEffect(() => {
if (printer?._id && connected) {
const temperatureEventUnsubscribe = subscribeToObjectEvent(
printer._id,
'printer',
'temperature',
(event) => {
if (event.data?.extruder?.current) {
setCurrentTemperature(event.data.extruder.current)
}
if (event.data?.extruder?.target) {
setTargetTemperature(event.data.extruder.target)
}
}
)
const filamentStockEventUnsubscribe = subscribeToObjectEvent(
printer._id,
'printer',
'filamentSensor',
(event) => {
console.log('filamentSensor', event.data)
setFilamentSensorDetected(event.data.detected)
}
)
return () => {
if (temperatureEventUnsubscribe) temperatureEventUnsubscribe()
if (filamentStockEventUnsubscribe) filamentStockEventUnsubscribe()
}
}
}, [printer?._id, connected])
useEffect(() => {
// Validate form fields
loadFilamentStockForm
.validateFields({
validateOnly: true
})
.then(() => {
const hasPrinter = Boolean(loadFilamentStockFormValues.printer)
const hasFilamentStock = Boolean(
loadFilamentStockFormValues.filamentStock
)
// Step 0 (Preheat): needs printer + filament detected + (temp reached or no temp set)
const preheatReady =
hasPrinter &&
filamentSensorDetected &&
(targetTemperature === 0 || currentTemperature >= targetTemperature)
// Step 1+ (Required/Summary): needs filamentStock selected
// Form is valid if preheat is ready (for step 0) OR filamentStock is selected (for step 1+)
// This allows progression: step 0 can proceed when preheat is ready,
// and step 1+ can proceed when filamentStock is selected
setFormValid(preheatReady || (hasPrinter && hasFilamentStock))
})
.catch(() => setFormValid(false))
}, [
loadFilamentStockForm,
loadFilamentStockFormUpdateValues,
loadFilamentStockFormValues,
filamentSensorDetected,
currentTemperature,
targetTemperature
])
const summaryItems = [
{
key: 'filamentStock',
label: 'Stock',
children: loadFilamentStockFormValues.filamentStock ? (
<ObjectDisplay
objectType='filamentStock'
object={loadFilamentStockFormValues.filamentStock}
/>
) : (
'n/a'
)
},
{
key: 'printer',
label: 'Printer',
children: loadFilamentStockFormValues.printer ? (
<ObjectDisplay
objectType='printer'
object={loadFilamentStockFormValues.printer}
/>
) : (
'n/a'
)
}
]
useEffect(() => {
if (reset) {
loadFilamentStockForm.resetFields()
}
}, [reset, loadFilamentStockForm])
const handleLoadFilamentStock = async () => {
setLoadFilamentStockLoading(true)
try {
// Set the extruder temperature
await sendObjectAction(
loadFilamentStockFormValues.printer._id,
'printer',
{
type: 'loadFilamentStock',
data: {
filamentStock: loadFilamentStockFormValues.filamentStock
}
}
)
onOk()
} finally {
setLoadFilamentStockLoading(false)
}
}
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'
}
]}
>
<ObjectSelect type='printer' checkable={false} />
</Form.Item>
{targetTemperature == 0 ? (
<Alert
message={'Heat the extruder to begin loading filament.'}
type='info'
showIcon
/>
) : null}
{targetTemperature > 0 && currentTemperature < targetTemperature ? (
<Alert
message={'Heating extruder...'}
type='error'
showIcon
icon={<LoadingOutlined />}
/>
) : null}
{targetTemperature > 0 &&
currentTemperature >= targetTemperature &&
filamentSensorDetected == false ? (
<Alert
message={'Insert filament to continue'}
type='success'
showIcon
/>
) : null}
{loadFilamentStockFormValues.printer ? (
<PrinterTemperaturePanel
showBed={false}
showMoreInfo={false}
id={loadFilamentStockFormValues.printer._id}
/>
) : null}
</Flex>
)
},
{
title: 'Required',
key: 'required',
content: (
<>
<Form.Item
label='Stock:'
name='filamentStock'
rules={[
{
required: true,
message: 'Please enter a G Code File.'
}
]}
>
<ObjectSelect type='filamentStock' />
</Form.Item>
</>
)
},
{
title: 'Summary',
key: 'summary',
content: (
<Form.Item>
<Descriptions column={1} items={summaryItems} size={'small'} />
</Form.Item>
)
}
]
return (
<Form
name='loadFilamentStock'
autoComplete='off'
form={loadFilamentStockForm}
onFinish={handleLoadFilamentStock}
onValuesChange={(changedValues) =>
setLoadFilamentStockFormValues((prevValues) => ({
...prevValues,
...changedValues
}))
}
initialValues={initialLoadFilamentStockForm}
>
<WizardView
title='Load Filament Stock'
steps={steps}
onSubmit={() => loadFilamentStockForm.submit()}
formValid={formValid}
loading={loadFilamentStockLoading}
submitText='Done'
/>
</Form>
)
}
export default LoadFilamentStock