Added better UI and implmented missing features
This commit is contained in:
parent
ce8f4cb038
commit
b39e761546
@ -174,7 +174,7 @@ const AppContent = () => {
|
|||||||
path='*'
|
path='*'
|
||||||
element={
|
element={
|
||||||
<AppError
|
<AppError
|
||||||
message='404! Page not found.'
|
message='Error 404. Page not found.'
|
||||||
showRefresh={false}
|
showRefresh={false}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,11 @@ import {
|
|||||||
Modal,
|
Modal,
|
||||||
message,
|
message,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
Typography
|
Typography,
|
||||||
|
Popover,
|
||||||
|
Checkbox,
|
||||||
|
Input,
|
||||||
|
Spin
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
@ -27,6 +31,9 @@ import PlusIcon from '../../Icons/PlusIcon'
|
|||||||
import ReloadIcon from '../../Icons/ReloadIcon'
|
import ReloadIcon from '../../Icons/ReloadIcon'
|
||||||
import FilamentStockState from '../common/FilamentStockState'
|
import FilamentStockState from '../common/FilamentStockState'
|
||||||
import TimeDisplay from '../common/TimeDisplay'
|
import TimeDisplay from '../common/TimeDisplay'
|
||||||
|
import XMarkIcon from '../../Icons/XMarkIcon'
|
||||||
|
import CheckIcon from '../../Icons/CheckIcon'
|
||||||
|
import useColumnVisibility from '../hooks/useColumnVisibility'
|
||||||
|
|
||||||
import config from '../../../config'
|
import config from '../../../config'
|
||||||
|
|
||||||
@ -57,38 +64,105 @@ const FilamentStocks = () => {
|
|||||||
const { socket } = useContext(SocketContext)
|
const { socket } = useContext(SocketContext)
|
||||||
|
|
||||||
const [filamentStocksData, setFilamentStocksData] = useState([])
|
const [filamentStocksData, setFilamentStocksData] = useState([])
|
||||||
|
const [page, setPage] = useState(1)
|
||||||
|
const [hasMore, setHasMore] = useState(true)
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [lazyLoading, setLazyLoading] = useState(false)
|
||||||
|
|
||||||
|
const [filters, setFilters] = useState({})
|
||||||
|
const [sorter, setSorter] = useState({
|
||||||
|
field: 'createdAt',
|
||||||
|
order: 'descend'
|
||||||
|
})
|
||||||
|
|
||||||
const [newFilamentStockOpen, setNewFilamentStockOpen] = useState(false)
|
const [newFilamentStockOpen, setNewFilamentStockOpen] = useState(false)
|
||||||
|
|
||||||
const [loading, setLoading] = useState(true)
|
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
|
|
||||||
const { authenticated } = useContext(AuthContext)
|
const { authenticated } = useContext(AuthContext)
|
||||||
|
|
||||||
const fetchFilamentStocksData = useCallback(async () => {
|
const getFilterDropdown = ({
|
||||||
try {
|
setSelectedKeys,
|
||||||
const response = await axios.get(`${config.backendUrl}/filamentstocks`, {
|
selectedKeys,
|
||||||
headers: {
|
confirm,
|
||||||
Accept: 'application/json'
|
clearFilters,
|
||||||
},
|
propertyName
|
||||||
withCredentials: true // Important for including cookies
|
}) => {
|
||||||
})
|
return (
|
||||||
setFilamentStocksData(response.data)
|
<div style={{ padding: 8 }}>
|
||||||
setLoading(false)
|
<Space.Compact>
|
||||||
} catch (err) {
|
<Input
|
||||||
messageApi.info(err)
|
placeholder={'Search ' + propertyName}
|
||||||
}
|
value={selectedKeys[0]}
|
||||||
}, [messageApi])
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchFilamentStocksData = useCallback(
|
||||||
|
async (pageNum = 1, append = false) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(
|
||||||
|
`${config.backendUrl}/filamentstocks`,
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
page: pageNum,
|
||||||
|
limit: 25,
|
||||||
|
...filters,
|
||||||
|
sort: sorter.field,
|
||||||
|
order: sorter.order
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json'
|
||||||
|
},
|
||||||
|
withCredentials: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const newData = response.data
|
||||||
|
setHasMore(newData.length === 25)
|
||||||
|
|
||||||
|
if (append) {
|
||||||
|
setFilamentStocksData((prev) => [...prev, ...newData])
|
||||||
|
} else {
|
||||||
|
setFilamentStocksData(newData)
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false)
|
||||||
|
setLazyLoading(false)
|
||||||
|
} catch (err) {
|
||||||
|
messageApi.error('Error fetching filament stocks:', err)
|
||||||
|
setLoading(false)
|
||||||
|
setLazyLoading(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[messageApi, filters, sorter]
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Fetch initial data
|
|
||||||
if (authenticated) {
|
if (authenticated) {
|
||||||
fetchFilamentStocksData()
|
fetchFilamentStocksData()
|
||||||
}
|
}
|
||||||
}, [authenticated, fetchFilamentStocksData])
|
}, [authenticated, fetchFilamentStocksData])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Add WebSocket event listener for real-time updates
|
|
||||||
if (socket && !initialized) {
|
if (socket && !initialized) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_filamentstock_update', (updateData) => {
|
socket.on('notify_filamentstock_update', (updateData) => {
|
||||||
@ -134,6 +208,43 @@ const FilamentStocks = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleScroll = useCallback(
|
||||||
|
(e) => {
|
||||||
|
const { target } = e
|
||||||
|
const scrollHeight = target.scrollHeight
|
||||||
|
const scrollTop = target.scrollTop
|
||||||
|
const clientHeight = target.clientHeight
|
||||||
|
|
||||||
|
if (
|
||||||
|
scrollHeight - scrollTop - clientHeight < 100 &&
|
||||||
|
!lazyLoading &&
|
||||||
|
hasMore
|
||||||
|
) {
|
||||||
|
setLazyLoading(true)
|
||||||
|
const nextPage = page + 1
|
||||||
|
setPage(nextPage)
|
||||||
|
fetchFilamentStocksData(nextPage, true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[page, lazyLoading, hasMore, fetchFilamentStocksData]
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
const newFilters = {}
|
||||||
|
Object.entries(filters).forEach(([key, value]) => {
|
||||||
|
if (value && value.length > 0) {
|
||||||
|
newFilters[key] = value[0]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setPage(1)
|
||||||
|
setFilters(newFilters)
|
||||||
|
setSorter({
|
||||||
|
field: sorter.field,
|
||||||
|
order: sorter.order
|
||||||
|
})
|
||||||
|
fetchFilamentStocksData(1)
|
||||||
|
}
|
||||||
|
|
||||||
// Column definitions
|
// Column definitions
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@ -150,6 +261,20 @@ const FilamentStocks = () => {
|
|||||||
key: 'name',
|
key: 'name',
|
||||||
width: 200,
|
width: 200,
|
||||||
fixed: 'left',
|
fixed: 'left',
|
||||||
|
sorter: true,
|
||||||
|
filterDropdown: ({
|
||||||
|
setSelectedKeys,
|
||||||
|
selectedKeys,
|
||||||
|
confirm,
|
||||||
|
clearFilters
|
||||||
|
}) =>
|
||||||
|
getFilterDropdown({
|
||||||
|
setSelectedKeys,
|
||||||
|
selectedKeys,
|
||||||
|
confirm,
|
||||||
|
clearFilters,
|
||||||
|
propertyName: 'filament name'
|
||||||
|
}),
|
||||||
render: (filament) => <Text ellipsis>{filament.name}</Text>
|
render: (filament) => <Text ellipsis>{filament.name}</Text>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -171,7 +296,8 @@ const FilamentStocks = () => {
|
|||||||
title: 'Current (g)',
|
title: 'Current (g)',
|
||||||
dataIndex: 'currentNetWeight',
|
dataIndex: 'currentNetWeight',
|
||||||
key: 'currentNetWeight',
|
key: 'currentNetWeight',
|
||||||
width: 120,
|
width: 140,
|
||||||
|
sorter: true,
|
||||||
render: (currentNetWeight) => (
|
render: (currentNetWeight) => (
|
||||||
<Text ellipsis>{currentNetWeight.toFixed(2) + 'g'}</Text>
|
<Text ellipsis>{currentNetWeight.toFixed(2) + 'g'}</Text>
|
||||||
)
|
)
|
||||||
@ -180,7 +306,8 @@ const FilamentStocks = () => {
|
|||||||
title: 'Starting (g)',
|
title: 'Starting (g)',
|
||||||
dataIndex: 'startingNetWeight',
|
dataIndex: 'startingNetWeight',
|
||||||
key: 'startingNetWeight',
|
key: 'startingNetWeight',
|
||||||
width: 120,
|
width: 140,
|
||||||
|
sorter: true,
|
||||||
render: (startingNetWeight) => (
|
render: (startingNetWeight) => (
|
||||||
<Text ellipsis>{startingNetWeight.toFixed(2) + 'g'}</Text>
|
<Text ellipsis>{startingNetWeight.toFixed(2) + 'g'}</Text>
|
||||||
)
|
)
|
||||||
@ -190,6 +317,8 @@ const FilamentStocks = () => {
|
|||||||
dataIndex: 'createdAt',
|
dataIndex: 'createdAt',
|
||||||
key: 'createdAt',
|
key: 'createdAt',
|
||||||
width: 180,
|
width: 180,
|
||||||
|
sorter: true,
|
||||||
|
defaultSortOrder: 'descend',
|
||||||
render: (createdAt) => {
|
render: (createdAt) => {
|
||||||
if (createdAt) {
|
if (createdAt) {
|
||||||
return <TimeDisplay dateTime={createdAt} />
|
return <TimeDisplay dateTime={createdAt} />
|
||||||
@ -203,6 +332,7 @@ const FilamentStocks = () => {
|
|||||||
dataIndex: 'updatedAt',
|
dataIndex: 'updatedAt',
|
||||||
key: 'updatedAt',
|
key: 'updatedAt',
|
||||||
width: 180,
|
width: 180,
|
||||||
|
sorter: true,
|
||||||
render: (updatedAt) => {
|
render: (updatedAt) => {
|
||||||
if (updatedAt) {
|
if (updatedAt) {
|
||||||
return <TimeDisplay dateTime={updatedAt} />
|
return <TimeDisplay dateTime={updatedAt} />
|
||||||
@ -236,6 +366,39 @@ const FilamentStocks = () => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
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 [columnVisibility, updateColumnVisibility] = useColumnVisibility(
|
||||||
|
'FilamentStocks',
|
||||||
|
columns
|
||||||
|
)
|
||||||
|
|
||||||
|
const visibleColumns = columns.filter(
|
||||||
|
(col) => !col.key || columnVisibility[col.key]
|
||||||
|
)
|
||||||
|
|
||||||
const actionItems = {
|
const actionItems = {
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
@ -252,7 +415,8 @@ const FilamentStocks = () => {
|
|||||||
],
|
],
|
||||||
onClick: ({ key }) => {
|
onClick: ({ key }) => {
|
||||||
if (key === 'reloadList') {
|
if (key === 'reloadList') {
|
||||||
fetchFilamentStocksData()
|
setPage(1)
|
||||||
|
fetchFilamentStocksData(1)
|
||||||
} else if (key === 'newFilamentStock') {
|
} else if (key === 'newFilamentStock') {
|
||||||
setNewFilamentStockOpen(true)
|
setNewFilamentStockOpen(true)
|
||||||
}
|
}
|
||||||
@ -263,19 +427,32 @@ const FilamentStocks = () => {
|
|||||||
<>
|
<>
|
||||||
<Flex vertical={'true'} gap='large'>
|
<Flex vertical={'true'} gap='large'>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
<Space>
|
<Flex justify={'space-between'}>
|
||||||
<Dropdown menu={actionItems}>
|
<Space size='small'>
|
||||||
<Button>Actions</Button>
|
<Dropdown menu={actionItems}>
|
||||||
</Dropdown>
|
<Button>Actions</Button>
|
||||||
</Space>
|
</Dropdown>
|
||||||
|
<Popover
|
||||||
|
content={getViewDropdownItems()}
|
||||||
|
placement='bottomLeft'
|
||||||
|
arrow={false}
|
||||||
|
>
|
||||||
|
<Button>View</Button>
|
||||||
|
</Popover>
|
||||||
|
</Space>
|
||||||
|
{lazyLoading && <Spin indicator={<LoadingOutlined />} />}
|
||||||
|
</Flex>
|
||||||
<Table
|
<Table
|
||||||
dataSource={filamentStocksData}
|
dataSource={filamentStocksData}
|
||||||
className={styles.customTable}
|
className={styles.customTable}
|
||||||
columns={columns}
|
columns={visibleColumns}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
rowKey='_id'
|
rowKey='_id'
|
||||||
loading={{ spinning: loading, indicator: <LoadingOutlined spin /> }}
|
loading={{ spinning: loading, indicator: <LoadingOutlined spin /> }}
|
||||||
scroll={{ y: 'calc(100vh - 270px)' }}
|
scroll={{ y: 'calc(100vh - 270px)' }}
|
||||||
|
onScroll={handleScroll}
|
||||||
|
onChange={handleTableChange}
|
||||||
|
showSorterTooltip={false}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@ -11,11 +11,11 @@ import {
|
|||||||
Checkbox,
|
Checkbox,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
Table,
|
Table,
|
||||||
Typography
|
Typography,
|
||||||
|
Input
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined, AuditOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, AuditOutlined } from '@ant-design/icons'
|
||||||
import moment from 'moment'
|
|
||||||
|
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { SocketContext } from '../context/SocketContext'
|
||||||
@ -25,6 +25,9 @@ import ReloadIcon from '../../Icons/ReloadIcon'
|
|||||||
import PlusMinusIcon from '../../Icons/PlusMinusIcon'
|
import PlusMinusIcon from '../../Icons/PlusMinusIcon'
|
||||||
import SubJobIcon from '../../Icons/SubJobIcon'
|
import SubJobIcon from '../../Icons/SubJobIcon'
|
||||||
import PlayCircleIcon from '../../Icons/PlayCircleIcon'
|
import PlayCircleIcon from '../../Icons/PlayCircleIcon'
|
||||||
|
import XMarkIcon from '../../Icons/XMarkIcon'
|
||||||
|
import CheckIcon from '../../Icons/CheckIcon'
|
||||||
|
import useColumnVisibility from '../hooks/useColumnVisibility'
|
||||||
|
|
||||||
import config from '../../../config'
|
import config from '../../../config'
|
||||||
|
|
||||||
@ -54,6 +57,16 @@ const StockEvents = () => {
|
|||||||
const { socket } = useContext(SocketContext)
|
const { socket } = useContext(SocketContext)
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
|
|
||||||
|
// Helper function to convert text to camelCase
|
||||||
|
const toCamelCase = (text) => {
|
||||||
|
return text
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
|
||||||
|
return index === 0 ? word.toLowerCase() : word.toUpperCase()
|
||||||
|
})
|
||||||
|
.replace(/\s+/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
const [stockEventsData, setStockEventsData] = useState([])
|
const [stockEventsData, setStockEventsData] = useState([])
|
||||||
const [page, setPage] = useState(1)
|
const [page, setPage] = useState(1)
|
||||||
const [hasMore, setHasMore] = useState(true)
|
const [hasMore, setHasMore] = useState(true)
|
||||||
@ -61,7 +74,10 @@ const StockEvents = () => {
|
|||||||
const [lazyLoading, setLazyLoading] = useState(false)
|
const [lazyLoading, setLazyLoading] = useState(false)
|
||||||
|
|
||||||
const [filters, setFilters] = useState({})
|
const [filters, setFilters] = useState({})
|
||||||
const [sorter, setSorter] = useState({})
|
const [sorter, setSorter] = useState({
|
||||||
|
field: 'createdAt',
|
||||||
|
order: 'descend'
|
||||||
|
})
|
||||||
|
|
||||||
// Column definitions for visibility
|
// Column definitions for visibility
|
||||||
const columns = [
|
const columns = [
|
||||||
@ -87,40 +103,27 @@ const StockEvents = () => {
|
|||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
key: 'type',
|
key: 'type',
|
||||||
width: 200,
|
width: 200,
|
||||||
sorter: (a, b) => a.type.localeCompare(b.type),
|
sorter: true,
|
||||||
filters: [
|
filterDropdown: ({
|
||||||
{ text: 'Sub Job', value: 'Sub Job' },
|
setSelectedKeys,
|
||||||
{ text: 'Audit Adjustment', value: 'Audit Adjustment' },
|
selectedKeys,
|
||||||
{ text: 'Initial', value: 'Initial' }
|
confirm,
|
||||||
],
|
clearFilters
|
||||||
onFilter: (value, record) => {
|
}) =>
|
||||||
const recordType = record.type.toLowerCase()
|
getFilterDropdown({
|
||||||
if (recordType === 'subjob') {
|
setSelectedKeys,
|
||||||
return value === 'Sub Job'
|
selectedKeys,
|
||||||
} else if (recordType === 'audit') {
|
confirm,
|
||||||
return value === 'Audit Adjustment'
|
clearFilters,
|
||||||
}
|
propertyName: 'type'
|
||||||
return (
|
})
|
||||||
value === recordType.charAt(0).toUpperCase() + recordType.slice(1)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
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 />,
|
title: <PlusMinusIcon />,
|
||||||
dataIndex: 'value',
|
dataIndex: 'value',
|
||||||
key: 'value',
|
key: 'value',
|
||||||
width: 100,
|
width: 100,
|
||||||
sorter: (a, b) => a.value - b.value,
|
sorter: true,
|
||||||
render: (value, record) => {
|
render: (value, record) => {
|
||||||
const formattedValue = value.toFixed(2) + record.unit
|
const formattedValue = value.toFixed(2) + record.unit
|
||||||
return (
|
return (
|
||||||
@ -180,8 +183,8 @@ const StockEvents = () => {
|
|||||||
dataIndex: 'createdAt',
|
dataIndex: 'createdAt',
|
||||||
key: 'createdAt',
|
key: 'createdAt',
|
||||||
width: 180,
|
width: 180,
|
||||||
|
sorter: true,
|
||||||
defaultSortOrder: 'descend',
|
defaultSortOrder: 'descend',
|
||||||
sorter: (a, b) => moment(a.createdAt).unix() - moment(b.createdAt).unix(),
|
|
||||||
render: (createdAt) => {
|
render: (createdAt) => {
|
||||||
if (createdAt) {
|
if (createdAt) {
|
||||||
return <TimeDisplay dateTime={createdAt} />
|
return <TimeDisplay dateTime={createdAt} />
|
||||||
@ -195,7 +198,7 @@ const StockEvents = () => {
|
|||||||
dataIndex: 'updatedAt',
|
dataIndex: 'updatedAt',
|
||||||
key: 'updatedAt',
|
key: 'updatedAt',
|
||||||
width: 180,
|
width: 180,
|
||||||
sorter: (a, b) => moment(a.updatedAt).unix() - moment(b.updatedAt).unix(),
|
sorter: true,
|
||||||
render: (updatedAt) => {
|
render: (updatedAt) => {
|
||||||
if (updatedAt) {
|
if (updatedAt) {
|
||||||
return <TimeDisplay dateTime={updatedAt} />
|
return <TimeDisplay dateTime={updatedAt} />
|
||||||
@ -206,15 +209,47 @@ const StockEvents = () => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const [columnVisibility, setColumnVisibility] = useState(
|
const [columnVisibility, updateColumnVisibility] = useColumnVisibility(
|
||||||
columns.reduce((acc, col) => {
|
'StockEvents',
|
||||||
if (col.key) {
|
columns
|
||||||
acc[col.key] = true
|
|
||||||
}
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const { authenticated } = useContext(AuthContext)
|
const { authenticated } = useContext(AuthContext)
|
||||||
|
|
||||||
const fetchStockEventsData = useCallback(
|
const fetchStockEventsData = useCallback(
|
||||||
@ -224,6 +259,7 @@ const StockEvents = () => {
|
|||||||
params: {
|
params: {
|
||||||
page: pageNum,
|
page: pageNum,
|
||||||
limit: 25,
|
limit: 25,
|
||||||
|
type: filters.type,
|
||||||
...filters,
|
...filters,
|
||||||
sort: sorter.field,
|
sort: sorter.field,
|
||||||
order: sorter.order
|
order: sorter.order
|
||||||
@ -341,7 +377,12 @@ const StockEvents = () => {
|
|||||||
const newFilters = {}
|
const newFilters = {}
|
||||||
Object.entries(filters).forEach(([key, value]) => {
|
Object.entries(filters).forEach(([key, value]) => {
|
||||||
if (value && value.length > 0) {
|
if (value && value.length > 0) {
|
||||||
newFilters[key] = value[0]
|
// Convert type filter to camelCase
|
||||||
|
if (key === 'type') {
|
||||||
|
newFilters[key] = toCamelCase(value[0])
|
||||||
|
} else {
|
||||||
|
newFilters[key] = value[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
setPage(1)
|
setPage(1)
|
||||||
@ -350,6 +391,8 @@ const StockEvents = () => {
|
|||||||
field: sorter.field,
|
field: sorter.field,
|
||||||
order: sorter.order
|
order: sorter.order
|
||||||
})
|
})
|
||||||
|
// Trigger a new fetch with the updated filters
|
||||||
|
fetchStockEventsData(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getViewDropdownItems = () => {
|
const getViewDropdownItems = () => {
|
||||||
@ -360,10 +403,7 @@ const StockEvents = () => {
|
|||||||
checked={columnVisibility[col.key]}
|
checked={columnVisibility[col.key]}
|
||||||
key={col.key}
|
key={col.key}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setColumnVisibility((prev) => ({
|
updateColumnVisibility(col.key, e.target.checked)
|
||||||
...prev,
|
|
||||||
[col.key]: e.target.checked
|
|
||||||
}))
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{col.title}
|
{col.title}
|
||||||
|
|||||||
@ -91,7 +91,7 @@ const Settings = () => {
|
|||||||
<Select
|
<Select
|
||||||
value={getCurrentThemeValue()}
|
value={getCurrentThemeValue()}
|
||||||
onChange={handleThemeChange}
|
onChange={handleThemeChange}
|
||||||
style={{ width: '200px' }}
|
style={{ width: '100%' }}
|
||||||
>
|
>
|
||||||
<Option value='light'>Light</Option>
|
<Option value='light'>Light</Option>
|
||||||
<Option value='dark'>Dark</Option>
|
<Option value='dark'>Dark</Option>
|
||||||
@ -102,7 +102,7 @@ const Settings = () => {
|
|||||||
<Select
|
<Select
|
||||||
value={isCompact ? 'compact' : 'comfortable'}
|
value={isCompact ? 'compact' : 'comfortable'}
|
||||||
onChange={handleCompactChange}
|
onChange={handleCompactChange}
|
||||||
style={{ width: '200px' }}
|
style={{ width: '100%' }}
|
||||||
>
|
>
|
||||||
<Option value='comfortable'>Comfortable</Option>
|
<Option value='comfortable'>Comfortable</Option>
|
||||||
<Option value='compact'>Compact</Option>
|
<Option value='compact'>Compact</Option>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user