Add PostFilamentStock Component and Update FilamentStock Model

- Introduced the PostFilamentStock component to handle posting filament stock with confirmation dialog and loading state management.
- Updated NewFilamentStock component to change the default state from 'unconsumed' to 'draft'.
- Enhanced FilamentStock model by adding 'postedAt' field and integrating the PostFilamentStock component into the actions for posting filament stocks.
- Improved visibility and disabled state logic for editing and posting actions based on filament stock state.
This commit is contained in:
Tom Butcher 2026-09-01 17:26:15 +01:00
parent 41825a23e5
commit 291d5e438c
3 changed files with 147 additions and 5 deletions

View File

@ -8,7 +8,7 @@ const NewFilamentStock = ({ onOk, reset, defaultValues }) => {
<NewObjectForm
type={'filamentStock'}
reset={reset}
defaultValues={{ state: { type: 'unconsumed' }, ...defaultValues }}
defaultValues={{ state: { type: 'draft' }, ...defaultValues }}
>
{({ handleSubmit, submitLoading, objectData, formValid }) => {
const steps = [
@ -38,7 +38,8 @@ const NewFilamentStock = ({ onOk, reset, defaultValues }) => {
_id: false,
_reference: false,
createdAt: false,
updatedAt: false
updatedAt: false,
postedAt: false
}}
isEditing={false}
objectData={objectData}

View File

@ -0,0 +1,46 @@
import { useState, useContext } from 'react'
import PropTypes from 'prop-types'
import { ApiServerContext } from '../../context/ApiServerContext'
import { message } from 'antd'
import MessageDialogView from '../../common/MessageDialogView.jsx'
const PostFilamentStock = ({ onOk, objectData }) => {
const [postLoading, setPostLoading] = useState(false)
const { sendObjectFunction } = useContext(ApiServerContext)
const handlePost = async () => {
setPostLoading(true)
try {
const result = await sendObjectFunction(
objectData._id,
'FilamentStock',
'post'
)
if (result) {
message.success('Filament stock posted successfully')
onOk(result)
}
} catch (error) {
console.error('Error posting filament stock:', error)
} finally {
setPostLoading(false)
}
}
return (
<MessageDialogView
title={'Are you sure you want to post this filament stock?'}
description={`Posting filament stock ${objectData?.name || objectData?._reference || objectData?._id} will finalize it and make it read-only.`}
onOk={handlePost}
okText='Post'
okLoading={postLoading}
/>
)
}
PostFilamentStock.propTypes = {
onOk: PropTypes.func.isRequired,
objectData: PropTypes.object
}
export default PostFilamentStock

View File

@ -8,9 +8,20 @@ const NewFilamentStock = lazy(
() =>
import('../../components/Dashboard/Inventory/FilamentStocks/NewFilamentStock')
)
const PostFilamentStock = lazy(
() =>
import('../../components/Dashboard/Inventory/FilamentStocks/PostFilamentStock.jsx')
)
const DeleteObject = lazy(
() => import('../../components/Dashboard/common/DeleteObject')
)
import FilamentStockIcon from '../../components/Icons/FilamentStockIcon'
import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
import BinIcon from '../../components/Icons/BinIcon'
import ListIcon from '../../components/Icons/ListIcon'
export const FilamentStock = {
@ -19,7 +30,6 @@ export const FilamentStock = {
labelPlural: 'Filament Stocks',
url: '/dashboard/inventory/filamentstocks',
prefix: 'FLS',
readOnly: true,
icon: FilamentStockIcon,
actions: [
{
@ -52,6 +62,76 @@ export const FilamentStock = {
default: true,
row: true,
icon: InfoCircleIcon
},
{
name: 'edit',
type: 'page',
pageName: 'info',
label: 'Edit',
row: true,
icon: EditIcon,
visible: (objectData) => {
return !(objectData?._isEditing && objectData?._isEditing == true)
},
disabled: (objectData) => {
return objectData?.state?.type != 'draft'
}
},
{
name: 'cancelEdit',
label: 'Cancel Edits',
type: 'page',
pageName: 'info',
icon: XMarkIcon,
visible: (objectData) => {
return objectData?._isEditing && objectData?._isEditing == true
}
},
{
name: 'finishEdit',
label: 'Save Edits',
type: 'page',
pageName: 'info',
icon: CheckIcon,
visible: (objectData) => {
return objectData?._isEditing && objectData?._isEditing == true
}
},
{
name: 'delete',
type: 'modal',
modalWidth: 520,
modalCentered: true,
label: 'Delete',
icon: BinIcon,
danger: true,
visible: (objectData) => {
return !(objectData?._isEditing && objectData?._isEditing == true)
},
disabled: (objectData) => {
return objectData?.state?.type != 'draft'
},
content: (objectData, { onOk } = {}) => {
return createElement(DeleteObject, { objectData, onOk })
}
},
{ type: 'divider' },
{
name: 'post',
type: 'modal',
modalWidth: 520,
modalCentered: true,
label: 'Post',
icon: CheckIcon,
disabled: (objectData) => {
return objectData?._isEditing == true
},
visible: (objectData) => {
return objectData?.state?.type == 'draft'
},
content: (objectData, { onOk } = {}) => {
return createElement(PostFilamentStock, { objectData, onOk })
}
}
],
pages: [
@ -126,6 +206,13 @@ export const FilamentStock = {
readOnly: true,
columnWidth: 260
},
{
name: 'postedAt',
label: 'Posted At',
type: 'dateTime',
readOnly: true,
columnWidth: 175
},
{
name: 'filament',
label: 'Filament',
@ -174,7 +261,10 @@ export const FilamentStock = {
required: true,
columnWidth: 300,
value: (objectData) => {
if (objectData?.state?.type === 'unconsumed') {
if (
objectData?.state?.type === 'unconsumed' ||
objectData?.state?.type === 'draft'
) {
return objectData?.startingWeight || { net: 0, gross: 0 }
} else {
return objectData?.currentWeight || { net: 0, gross: 0 }
@ -186,7 +276,6 @@ export const FilamentStock = {
label: 'Starting Weight',
type: 'netGross',
suffix: 'g',
readOnly: true,
initial: true,
required: true,
columnWidth: 300,
@ -196,6 +285,12 @@ export const FilamentStock = {
}
],
stats: [
{
name: 'draft.count',
label: 'Draft',
type: 'number',
color: 'default'
},
{
name: 'unconsumed.count',
label: 'Unconsumed',