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

240 lines
6.1 KiB
JavaScript

import { useEffect, useContext, useState } from 'react'
import { Table, Typography } from 'antd'
import PropTypes from 'prop-types'
import IdDisplay from './IdDisplay'
import { AuditOutlined } from '@ant-design/icons'
import { PrintServerContext } from '../context/PrintServerContext'
import moment from 'moment'
import TimeDisplay from '../common/TimeDisplay'
import PlusMinusIcon from '../../Icons/PlusMinusIcon'
import SubJobIcon from '../../Icons/SubJobIcon'
import PlayCircleIcon from '../../Icons/PlayCircleIcon'
const { Text } = Typography
const StockEventTable = ({ stockEvents }) => {
const { printServer } = useContext(PrintServerContext)
const [initialized, setInitialized] = useState(false)
const [stockEventsData, setStockEventsData] = useState(stockEvents)
useEffect(() => {
// Add WebSocket event listener for real-time updates
if (printServer && !initialized) {
setInitialized(true)
printServer.on('notify_stockevent_update', (updateData) => {
setStockEventsData((prevData) => {
return prevData.map((stockEvent) => {
if (stockEvent?._id) {
if (stockEvent._id === updateData._id) {
return {
...stockEvent,
...updateData
}
} else {
return stockEvent
}
}
})
})
})
}
return () => {
if (printServer && initialized) {
printServer.off('notify_stockevent_update')
}
}
}, [printServer, initialized])
useEffect(() => {
setStockEventsData(stockEvents)
}, [stockEvents])
const getTypeFilterProps = () => {
// Get unique types from the data
const uniqueTypes = [
...new Set(
stockEventsData.map((record) => {
const type = record.type.toLowerCase()
if (type === 'subjob') return 'Sub Job'
if (type === 'audit') return 'Audit Adjustment'
return type.charAt(0).toUpperCase() + type.slice(1)
})
)
]
return {
filters: uniqueTypes.map((type) => ({ text: type, value: type })),
onFilter: (value, record) => {
const recordType = record.type.toLowerCase()
if (recordType === 'subjob') {
return value === 'Sub Job'
} else if (recordType === 'audit') {
return value === 'Audit Adjustment'
}
return (
value === recordType.charAt(0).toUpperCase() + recordType.slice(1)
)
}
}
}
const columns = [
{
title: '',
key: 'icon',
width: 50,
render: (record) => {
switch (record.type.toLowerCase()) {
case 'subjob':
return <SubJobIcon />
case 'audit':
return <AuditOutlined />
case 'initial':
return <PlayCircleIcon />
default:
return null
}
}
},
{
title: 'Type',
dataIndex: 'type',
key: 'type',
width: 200,
sorter: (a, b) => a.type.localeCompare(b.type),
...getTypeFilterProps(),
render: (type) => {
switch (type.toLowerCase()) {
case 'subjob':
return 'Sub Job'
case 'audit':
return 'Audit Adjustment'
default:
return type.charAt(0).toUpperCase() + type.slice(1)
}
}
},
{
title: <PlusMinusIcon />,
dataIndex: 'value',
key: 'value',
width: 100,
sorter: (a, b) => a.value - b.value,
render: (value, record) => {
const formattedValue = value.toFixed(2) + record.unit
return (
<Text type={value < 0 ? 'danger' : 'success'}>
{value > 0 ? '+' + formattedValue : formattedValue}
</Text>
)
}
},
{
title: 'Linked ID',
width: 100,
render: (record) => {
if (record.subJob) {
return (
<IdDisplay
id={record.subJob.number.toString().padStart(6, '0')}
longId={false}
type={'subjob'}
/>
)
}
if (record.stockAudit) {
return (
<IdDisplay
id={record.stockAudit._id}
longId={false}
type={'stockaudit'}
showHyperlink={true}
/>
)
}
return 'n/a'
}
},
{
title: 'Job ID',
width: 100,
render: (record) => {
if (record.subJob) {
return (
<IdDisplay
id={record.job._id}
longId={false}
type={'job'}
showHyperlink={true}
/>
)
}
return 'n/a'
}
},
{
title: 'Created At',
dataIndex: 'createdAt',
key: 'createdAt',
width: 180,
defaultSortOrder: 'descend',
sorter: (a, b) => moment(a.createdAt).unix() - moment(b.createdAt).unix(),
render: (createdAt) => {
if (createdAt) {
return <TimeDisplay dateTime={createdAt} />
} else {
return 'n/a'
}
}
},
{
title: 'Updated At',
dataIndex: 'updatedAt',
key: 'updatedAt',
width: 180,
sorter: (a, b) => moment(a.updatedAt).unix() - moment(b.updatedAt).unix(),
render: (updatedAt) => {
if (updatedAt) {
return <TimeDisplay dateTime={updatedAt} />
} else {
return 'n/a'
}
}
}
]
return (
<Table
dataSource={stockEventsData}
columns={columns}
rowKey={(record) => record._id}
pagination={false}
scroll={{ x: 'max-content' }}
/>
)
}
StockEventTable.propTypes = {
stockEvents: PropTypes.arrayOf(
PropTypes.shape({
type: PropTypes.string.isRequired,
value: PropTypes.number.isRequired,
subJobId: PropTypes.shape({
$oid: PropTypes.string.isRequired
}),
jobId: PropTypes.shape({
$oid: PropTypes.string.isRequired
}),
timestamp: PropTypes.shape({
$date: PropTypes.string.isRequired
}),
_id: PropTypes.shape({
$oid: PropTypes.string.isRequired
}).isRequired
})
).isRequired
}
export default StockEventTable