212 lines
5.3 KiB
JavaScript
212 lines
5.3 KiB
JavaScript
import React, { useEffect, useState, useContext } from 'react'
|
|
import { useLocation, useNavigate } from 'react-router-dom'
|
|
import axios from 'axios'
|
|
import {
|
|
Card,
|
|
Descriptions,
|
|
Button,
|
|
Space,
|
|
message,
|
|
Typography,
|
|
Table,
|
|
Tag
|
|
} from 'antd'
|
|
import {
|
|
ArrowLeftOutlined,
|
|
LoadingOutlined,
|
|
ClockCircleOutlined
|
|
} from '@ant-design/icons'
|
|
|
|
import { AuthContext } from '../../context/AuthContext'
|
|
import IdText from '../../common/IdText'
|
|
import TimeDisplay from '../../common/TimeDisplay'
|
|
|
|
import config from '../../../../config'
|
|
import XMarkCircleIcon from '../../../Icons/XMarkCircleIcon'
|
|
import CheckCircleIcon from '../../../Icons/CheckCircleIcon'
|
|
|
|
const { Text, Title } = Typography
|
|
|
|
const StockAuditInfo = () => {
|
|
const [messageApi, contextHolder] = message.useMessage()
|
|
const location = useLocation()
|
|
const navigate = useNavigate()
|
|
const { authenticated } = useContext(AuthContext)
|
|
|
|
const [stockAudit, setStockAudit] = useState(null)
|
|
const [loading, setLoading] = useState(true)
|
|
|
|
const stockAuditId = new URLSearchParams(location.search).get('stockAuditId')
|
|
|
|
useEffect(() => {
|
|
const fetchStockAudit = async () => {
|
|
if (!stockAuditId) {
|
|
messageApi.error('No stock audit ID provided')
|
|
navigate('/dashboard/inventory/stockaudits')
|
|
return
|
|
}
|
|
|
|
try {
|
|
const response = await axios.get(
|
|
`${config.backendUrl}/stockaudits/${stockAuditId}`,
|
|
{
|
|
headers: {
|
|
Accept: 'application/json'
|
|
},
|
|
withCredentials: true
|
|
}
|
|
)
|
|
setStockAudit(response.data)
|
|
setLoading(false)
|
|
} catch (err) {
|
|
messageApi.error('Failed to fetch stock audit details')
|
|
navigate('/dashboard/inventory/stockaudits')
|
|
}
|
|
}
|
|
|
|
if (authenticated) {
|
|
fetchStockAudit()
|
|
}
|
|
}, [authenticated, stockAuditId, messageApi, navigate])
|
|
|
|
const getStatusTag = (status) => {
|
|
switch (status?.toLowerCase()) {
|
|
case 'completed':
|
|
return (
|
|
<Tag icon={<CheckCircleIcon />} color='success'>
|
|
Completed
|
|
</Tag>
|
|
)
|
|
case 'in_progress':
|
|
return (
|
|
<Tag icon={<ClockCircleOutlined />} color='processing'>
|
|
In Progress
|
|
</Tag>
|
|
)
|
|
case 'failed':
|
|
return (
|
|
<Tag icon={<XMarkCircleIcon />} color='error'>
|
|
Failed
|
|
</Tag>
|
|
)
|
|
default:
|
|
return (
|
|
<Tag icon={<ClockCircleOutlined />} color='default'>
|
|
Unknown
|
|
</Tag>
|
|
)
|
|
}
|
|
}
|
|
|
|
const auditItemsColumns = [
|
|
{
|
|
title: 'Item ID',
|
|
dataIndex: '_id',
|
|
key: 'id',
|
|
width: 165,
|
|
render: (text) => (
|
|
<IdText id={text} type={'stockaudititem'} longId={false} />
|
|
)
|
|
},
|
|
{
|
|
title: 'Item Type',
|
|
dataIndex: 'itemType',
|
|
key: 'itemType',
|
|
width: 120
|
|
},
|
|
{
|
|
title: 'Expected Weight',
|
|
dataIndex: 'expectedWeight',
|
|
key: 'expectedWeight',
|
|
width: 120,
|
|
render: (weight) => `${weight.toFixed(2)}g`
|
|
},
|
|
{
|
|
title: 'Actual Weight',
|
|
dataIndex: 'actualWeight',
|
|
key: 'actualWeight',
|
|
width: 120,
|
|
render: (weight) => `${weight.toFixed(2)}g`
|
|
},
|
|
{
|
|
title: 'Difference',
|
|
key: 'difference',
|
|
width: 120,
|
|
render: (_, record) => {
|
|
const diff = record.actualWeight - record.expectedWeight
|
|
return (
|
|
<Text type={diff === 0 ? 'success' : 'danger'}>
|
|
{diff.toFixed(2)}g
|
|
</Text>
|
|
)
|
|
}
|
|
},
|
|
{
|
|
title: 'Status',
|
|
dataIndex: 'status',
|
|
key: 'status',
|
|
width: 120,
|
|
render: (status) => getStatusTag(status)
|
|
}
|
|
]
|
|
|
|
if (loading) {
|
|
return (
|
|
<div style={{ textAlign: 'center', padding: '50px' }}>
|
|
<LoadingOutlined style={{ fontSize: 24 }} spin />
|
|
<Text style={{ marginLeft: 16 }}>Loading stock audit details...</Text>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (!stockAudit) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{contextHolder}
|
|
<Space direction='vertical' size='large' style={{ width: '100%' }}>
|
|
<Space>
|
|
<Button
|
|
icon={<ArrowLeftOutlined />}
|
|
onClick={() => navigate('/dashboard/inventory/stockaudits')}
|
|
>
|
|
Back to Stock Audits
|
|
</Button>
|
|
</Space>
|
|
|
|
<Card>
|
|
<Title level={4}>Stock Audit Details</Title>
|
|
<Descriptions bordered>
|
|
<Descriptions.Item label='ID'>
|
|
<IdText id={stockAudit._id} type={'stockaudit'} longId={true} />
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Status'>
|
|
{getStatusTag(stockAudit.status)}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Created At'>
|
|
<TimeDisplay dateTime={stockAudit.createdAt} showSince={true} />
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Updated At'>
|
|
<TimeDisplay dateTime={stockAudit.updatedAt} showSince={true} />
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
</Card>
|
|
|
|
<Card title='Audit Items'>
|
|
<Table
|
|
dataSource={stockAudit.items || []}
|
|
columns={auditItemsColumns}
|
|
rowKey='_id'
|
|
pagination={false}
|
|
scroll={{ y: 'calc(100vh - 500px)' }}
|
|
/>
|
|
</Card>
|
|
</Space>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default StockAuditInfo
|