|
- 'use client';
-
- import { fetchItemMovements, ItemMovementRow } from '@/app/api/inventory/actions';
- import { InventoryResult } from '@/app/api/inventory';
- import { useEffect, useMemo, useRef, useState } from 'react';
- import { useTranslation } from 'react-i18next';
- import { Box, CircularProgress, Typography } from '@mui/material';
- import { Column } from '../SearchResults';
- import SearchResults, { defaultPagingController } from '../SearchResults/SearchResults';
-
- interface Props {
- inventory: InventoryResult | null;
- }
-
- const InventoryItemLedger: React.FC<Props> = ({ inventory }) => {
- const { t } = useTranslation('inventory');
- const [rows, setRows] = useState<ItemMovementRow[]>([]);
- const [total, setTotal] = useState(0);
- const [loading, setLoading] = useState(false);
- const [pagingController, setPagingController] = useState(defaultPagingController);
- const requestRef = useRef(0);
- const itemId = inventory?.itemId;
-
- useEffect(() => {
- if (itemId == null) {
- setRows([]);
- setTotal(0);
- setLoading(false);
- return;
- }
- const requestId = ++requestRef.current;
- setLoading(true);
- fetchItemMovements({
- itemId,
- pageNum: pagingController.pageNum - 1,
- pageSize: pagingController.pageSize,
- })
- .then((res) => {
- if (requestId !== requestRef.current) return;
- setRows(res?.records ?? []);
- setTotal(res?.total ?? 0);
- })
- .catch((error) => {
- if (requestId !== requestRef.current) return;
- console.error('Failed to load item movements:', error);
- setRows([]);
- setTotal(0);
- })
- .finally(() => {
- if (requestId === requestRef.current) setLoading(false);
- });
- }, [itemId, pagingController]);
-
- const columns = useMemo<Column<ItemMovementRow>[]>(
- () => [
- { name: 'trnDate', label: t('Transaction Date') },
- {
- name: 'type',
- label: t('Type'),
- renderCell: (row) => (row.type ? t(row.type) : ''),
- },
- { name: 'lotNo', label: t('Lot No') },
- { name: 'expiryDate', label: t('Expiry Date') },
- {
- name: 'openingQty',
- label: t('Opening Qty'),
- align: 'right',
- headerAlign: 'right',
- type: 'integer',
- },
- {
- name: 'inQty',
- label: t('In Qty'),
- align: 'right',
- headerAlign: 'right',
- type: 'integer',
- },
- {
- name: 'outQty',
- label: t('Out Qty'),
- align: 'right',
- headerAlign: 'right',
- type: 'integer',
- },
- {
- name: 'balanceQty',
- label: t('Balance Qty'),
- align: 'right',
- headerAlign: 'right',
- type: 'integer',
- },
- { name: 'orderRefNo', label: t('Reference No') },
- { name: 'storeLocation', label: t('Store Location') },
- ],
- [t],
- );
-
- if (!inventory || itemId == null) {
- return <Typography sx={{ mt: 2 }}>{t('No items are selected yet.')}</Typography>;
- }
-
- return (
- <Box sx={{ mt: 1 }}>
- <Typography variant="h6" sx={{ mb: 1 }}>
- {`${t('Item selected')}: ${inventory.itemCode} | ${inventory.itemName} (${t(inventory.itemType)})`}
- </Typography>
- {loading && rows.length === 0 ? (
- <Box sx={{ display: 'flex', justifyContent: 'center', py: 4 }}>
- <CircularProgress size={28} />
- </Box>
- ) : (
- <SearchResults<ItemMovementRow>
- items={rows}
- columns={columns}
- pagingController={pagingController}
- setPagingController={setPagingController}
- totalCount={total}
- isAutoPaging={false}
- />
- )}
- </Box>
- );
- };
-
- export default InventoryItemLedger;
|