363 lines
9.0 KiB
JavaScript
363 lines
9.0 KiB
JavaScript
// src/filamentStocks.js
|
|
|
|
import React, { useState, useContext, useRef } from 'react'
|
|
import { useNavigate } from 'react-router-dom'
|
|
import {
|
|
Button,
|
|
Flex,
|
|
Space,
|
|
Modal,
|
|
Dropdown,
|
|
Typography,
|
|
message,
|
|
Checkbox,
|
|
Popover,
|
|
Input
|
|
} from 'antd'
|
|
|
|
import { AuthContext } from '../context/AuthContext'
|
|
import { PrintServerContext } from '../context/PrintServerContext'
|
|
|
|
import NewFilamentStock from './FilamentStocks/NewFilamentStock'
|
|
import IdText from '../common/IdText'
|
|
import FilamentStockIcon from '../../Icons/FilamentStockIcon'
|
|
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
|
import PlusIcon from '../../Icons/PlusIcon'
|
|
import ReloadIcon from '../../Icons/ReloadIcon'
|
|
import FilamentStockState from '../common/FilamentStockState'
|
|
import TimeDisplay from '../common/TimeDisplay'
|
|
import XMarkIcon from '../../Icons/XMarkIcon'
|
|
import CheckIcon from '../../Icons/CheckIcon'
|
|
import useColumnVisibility from '../hooks/useColumnVisibility'
|
|
import DashboardTable from '../common/DashboardTable'
|
|
import ListIcon from '../../Icons/ListIcon'
|
|
import GridIcon from '../../Icons/GridIcon'
|
|
import useViewMode from '../hooks/useViewMode'
|
|
|
|
import config from '../../../config'
|
|
|
|
const { Text } = Typography
|
|
|
|
const FilamentStocks = () => {
|
|
const [messageApi, contextHolder] = message.useMessage()
|
|
const navigate = useNavigate()
|
|
const { printServer } = useContext(PrintServerContext)
|
|
const [initialized, setInitialized] = useState(false)
|
|
const tableRef = useRef()
|
|
|
|
const [newFilamentStockOpen, setNewFilamentStockOpen] = useState(false)
|
|
|
|
const { authenticated } = useContext(AuthContext)
|
|
|
|
const [viewMode, setViewMode] = useViewMode('FilamentStocks')
|
|
|
|
const getFilterDropdown = ({
|
|
setSelectedKeys,
|
|
selectedKeys,
|
|
confirm,
|
|
clearFilters,
|
|
propertyName
|
|
}) => {
|
|
return (
|
|
<div style={{ padding: 8 }}>
|
|
<Space.Compact>
|
|
<Input
|
|
placeholder={'Search ' + propertyName}
|
|
value={selectedKeys[0]}
|
|
onChange={(e) =>
|
|
setSelectedKeys(e.target.value ? [e.target.value] : [])
|
|
}
|
|
onPressEnter={() => confirm()}
|
|
style={{ width: 200, display: 'block' }}
|
|
/>
|
|
<Button
|
|
onClick={() => {
|
|
clearFilters()
|
|
confirm()
|
|
}}
|
|
icon={<XMarkIcon />}
|
|
/>
|
|
<Button
|
|
type='primary'
|
|
onClick={() => confirm()}
|
|
icon={<CheckIcon />}
|
|
/>
|
|
</Space.Compact>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// Column definitions
|
|
const columns = [
|
|
{
|
|
title: <FilamentStockIcon />,
|
|
key: 'icon',
|
|
width: 40,
|
|
fixed: 'left',
|
|
render: () => <FilamentStockIcon />
|
|
},
|
|
{
|
|
title: 'Filament Name',
|
|
dataIndex: 'filament',
|
|
key: 'name',
|
|
width: 200,
|
|
fixed: 'left',
|
|
sorter: true,
|
|
filterDropdown: ({
|
|
setSelectedKeys,
|
|
selectedKeys,
|
|
confirm,
|
|
clearFilters
|
|
}) =>
|
|
getFilterDropdown({
|
|
setSelectedKeys,
|
|
selectedKeys,
|
|
confirm,
|
|
clearFilters,
|
|
propertyName: 'filament name'
|
|
}),
|
|
render: (filament) => <Text ellipsis>{filament?.name}</Text>
|
|
},
|
|
{
|
|
title: 'ID',
|
|
dataIndex: '_id',
|
|
key: 'id',
|
|
width: 180,
|
|
render: (text) => (
|
|
<IdText id={text} type={'filamentstock'} longId={false} />
|
|
)
|
|
},
|
|
{
|
|
title: 'State',
|
|
key: 'state',
|
|
width: 350,
|
|
render: (record) => <FilamentStockState filamentStock={record} />
|
|
},
|
|
{
|
|
title: 'Current (g)',
|
|
dataIndex: 'currentNetWeight',
|
|
key: 'currentNetWeight',
|
|
width: 140,
|
|
sorter: true,
|
|
render: (currentNetWeight) => (
|
|
<Text ellipsis>{currentNetWeight?.toFixed(2) + 'g'}</Text>
|
|
)
|
|
},
|
|
{
|
|
title: 'Starting (g)',
|
|
dataIndex: 'startingNetWeight',
|
|
key: 'startingNetWeight',
|
|
width: 140,
|
|
sorter: true,
|
|
render: (startingNetWeight) => (
|
|
<Text ellipsis>{startingNetWeight?.toFixed(2) + 'g'}</Text>
|
|
)
|
|
},
|
|
{
|
|
title: 'Created At',
|
|
dataIndex: 'createdAt',
|
|
key: 'createdAt',
|
|
width: 180,
|
|
sorter: true,
|
|
defaultSortOrder: 'descend',
|
|
render: (createdAt) => {
|
|
if (createdAt) {
|
|
return <TimeDisplay dateTime={createdAt} />
|
|
} else {
|
|
return 'n/a'
|
|
}
|
|
}
|
|
},
|
|
{
|
|
title: 'Updated At',
|
|
dataIndex: 'updatedAt',
|
|
key: 'updatedAt',
|
|
width: 180,
|
|
sorter: true,
|
|
render: (updatedAt) => {
|
|
if (updatedAt) {
|
|
return <TimeDisplay dateTime={updatedAt} />
|
|
} else {
|
|
return 'n/a'
|
|
}
|
|
}
|
|
},
|
|
{
|
|
title: 'Actions',
|
|
key: 'actions',
|
|
fixed: 'right',
|
|
width: 150,
|
|
render: (record) => {
|
|
return (
|
|
<Space gap='small'>
|
|
<Button
|
|
icon={<InfoCircleIcon />}
|
|
onClick={() =>
|
|
navigate(
|
|
`/dashboard/inventory/filamentstocks/info?filamentStockId=${record._id}`
|
|
)
|
|
}
|
|
/>
|
|
<Dropdown menu={getFilamentStockActionItems(record._id)}>
|
|
<Button>Actions</Button>
|
|
</Dropdown>
|
|
</Space>
|
|
)
|
|
}
|
|
}
|
|
]
|
|
|
|
const [columnVisibility, updateColumnVisibility] = useColumnVisibility(
|
|
'FilamentStocks',
|
|
columns
|
|
)
|
|
|
|
React.useEffect(() => {
|
|
if (printServer && !initialized) {
|
|
setInitialized(true)
|
|
printServer.on('notify_filamentstock_update', (updateData) => {
|
|
console.log('Received filament stock update:', updateData)
|
|
if (tableRef.current) {
|
|
tableRef.current.updateData(updateData._id, updateData)
|
|
}
|
|
})
|
|
}
|
|
|
|
return () => {
|
|
if (printServer && initialized) {
|
|
console.log('Deregistering filament stock update listener')
|
|
printServer.off('notify_filamentstock_update')
|
|
}
|
|
}
|
|
}, [printServer, initialized])
|
|
|
|
const getFilamentStockActionItems = (id) => {
|
|
return {
|
|
items: [
|
|
{
|
|
label: 'Info',
|
|
key: 'info',
|
|
icon: <InfoCircleIcon />
|
|
}
|
|
],
|
|
onClick: ({ key }) => {
|
|
if (key === 'info') {
|
|
navigate(
|
|
`/dashboard/inventory/filamentstocks/info?filamentStockId=${id}`
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const actionItems = {
|
|
items: [
|
|
{
|
|
label: 'New Filament Stock',
|
|
key: 'newFilamentStock',
|
|
icon: <PlusIcon />
|
|
},
|
|
{ type: 'divider' },
|
|
{
|
|
label: 'Reload List',
|
|
key: 'reloadList',
|
|
icon: <ReloadIcon />
|
|
}
|
|
],
|
|
onClick: ({ key }) => {
|
|
if (key === 'reloadList') {
|
|
tableRef.current?.reload()
|
|
} else if (key === 'newFilamentStock') {
|
|
setNewFilamentStockOpen(true)
|
|
}
|
|
}
|
|
}
|
|
|
|
const getViewDropdownItems = () => {
|
|
const columnItems = columns
|
|
.filter((col) => col.key && col.title !== '')
|
|
.map((col) => (
|
|
<Checkbox
|
|
checked={columnVisibility[col.key]}
|
|
key={col.key}
|
|
onChange={(e) => {
|
|
updateColumnVisibility(col.key, e.target.checked)
|
|
}}
|
|
>
|
|
{col.title}
|
|
</Checkbox>
|
|
))
|
|
|
|
return (
|
|
<Flex vertical>
|
|
<Flex vertical gap='middle' style={{ margin: '4px 8px' }}>
|
|
{columnItems}
|
|
</Flex>
|
|
</Flex>
|
|
)
|
|
}
|
|
|
|
const visibleColumns = columns.filter(
|
|
(col) => !col.key || columnVisibility[col.key]
|
|
)
|
|
|
|
return (
|
|
<>
|
|
<Flex vertical={'true'} gap='large'>
|
|
{contextHolder}
|
|
<Flex justify={'space-between'}>
|
|
<Space size='small'>
|
|
<Dropdown menu={actionItems}>
|
|
<Button>Actions</Button>
|
|
</Dropdown>
|
|
<Popover
|
|
content={getViewDropdownItems()}
|
|
placement='bottomLeft'
|
|
arrow={false}
|
|
>
|
|
<Button>View</Button>
|
|
</Popover>
|
|
</Space>
|
|
<Space>
|
|
<Button
|
|
icon={viewMode === 'cards' ? <ListIcon /> : <GridIcon />}
|
|
onClick={() =>
|
|
setViewMode(viewMode === 'cards' ? 'list' : 'cards')
|
|
}
|
|
/>
|
|
</Space>
|
|
</Flex>
|
|
|
|
<DashboardTable
|
|
ref={tableRef}
|
|
columns={visibleColumns}
|
|
url={`${config.backendUrl}/filamentstocks`}
|
|
authenticated={authenticated}
|
|
cards={viewMode === 'cards'}
|
|
/>
|
|
</Flex>
|
|
<Modal
|
|
open={newFilamentStockOpen}
|
|
styles={{ content: { paddingBottom: '24px' } }}
|
|
footer={null}
|
|
width={700}
|
|
onCancel={() => {
|
|
setNewFilamentStockOpen(false)
|
|
}}
|
|
destroyOnHidden={true}
|
|
>
|
|
<NewFilamentStock
|
|
onOk={() => {
|
|
setNewFilamentStockOpen(false)
|
|
messageApi.success('New filament stock created successfully.')
|
|
tableRef.current?.reload()
|
|
}}
|
|
reset={newFilamentStockOpen}
|
|
/>
|
|
</Modal>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default FilamentStocks
|