@@ -1,13 +1,9 @@
"use client";
"use client";
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import {
import {
Box,
Box,
Typography,
Typography,
FormControl,
InputLabel,
Select,
MenuItem,
Card,
Card,
CardContent,
CardContent,
Stack,
Stack,
@@ -19,88 +15,112 @@ import {
TableRow,
TableRow,
Paper,
Paper,
CircularProgress,
CircularProgress,
Chip
Button
} from '@mui/material';
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import { useTranslation } from 'react-i18next';
import dayjs from 'dayjs';
import dayjs from 'dayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { fetchGoodsReceiptStatusClient, type GoodsReceiptStatusRow } from '@/app/api/dashboard/client';
interface GoodsReceiptStatusItem {
id: string;
}
const REFRESH_MS = 15 * 60 * 1000;
const GoodsReceiptStatus: React.FC = () => {
const GoodsReceiptStatus: React.FC = () => {
const { t } = useTranslation("dashboard");
const { t } = useTranslation("dashboard");
const [selectedFilter, setSelectedFilter] = useState<string>("");
const [data, setData] = useState<GoodsReceiptStatusItem[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [currentTime, setCurrentTime] = useState<dayjs.Dayjs | null>(null);
const [isClient, setIsClient] = useState<boolean>(false);
useEffect(() => {
setIsClient(true);
setCurrentTime(dayjs());
}, []);
const [selectedDate, setSelectedDate] = useState<dayjs.Dayjs>(dayjs());
const [data, setData] = useState<GoodsReceiptStatusRow[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [lastUpdated, setLastUpdated] = useState<dayjs.Dayjs | null>(null);
const [screenCleared, setScreenCleared] = useState<boolean>(false);
const loadData = useCallback(async () => {
const loadData = useCallback(async () => {
if (screenCleared) return;
try {
try {
setData([]);
setLoading(true);
const dateParam = selectedDate.format('YYYY-MM-DD');
const result = await fetchGoodsReceiptStatusClient(dateParam);
setData(result ?? []);
setLastUpdated(dayjs());
} catch (error) {
} catch (error) {
console.error('Error fetching goods receipt status:', error);
console.error('Error fetching goods receipt status:', error);
setData([]);
} finally {
} finally {
setLoading(false);
setLoading(false);
}
}
}, []);
}, [selectedDate, screenCleared ]);
useEffect(() => {
useEffect(() => {
if (screenCleared) return;
loadData();
loadData();
const refreshInterval = setInterval(() => {
const refreshInterval = setInterval(() => {
loadData();
loadData();
}, 5 * 60 * 1000);
}, REFRESH_MS);
return () => clearInterval(refreshInterval);
return () => clearInterval(refreshInterval);
}, [loadData]);
}, [loadData, screenCleared ]);
useEffect(() => {
if (!isClient) return;
const timeInterval = setInterval(() => {
setCurrentTime(dayjs());
}, 60 * 1000);
return () => clearInterval(timeInterval);
}, [isClient]);
const filteredData = useMemo(() => {
if (!selectedFilter) return data;
return data.filter(item => true);
}, [data, selectedFilter]);
const selectedDateLabel = useMemo(() => {
return selectedDate.format('YYYY-MM-DD');
}, [selectedDate]);
if (screenCleared) {
return (
<Card sx={{ mb: 2 }}>
<CardContent>
<Stack direction="row" spacing={2} justifyContent="space-between" alignItems="center">
<Typography variant="body2" color="text.secondary">
{t("Screen cleared")}
</Typography>
<Button variant="contained" onClick={() => setScreenCleared(false)}>
{t("Restore Screen")}
</Button>
</Stack>
</CardContent>
</Card>
);
}
return (
return (
<Card sx={{ mb: 2 }}>
<Card sx={{ mb: 2 }}>
<CardContent>
<CardContent>
{/* Filter */}
<Stack direction="row" spacing={2} sx={{ mb: 3 }}>
<FormControl sx={{ minWidth: 150 }} size="small">
<InputLabel id="filter-select-label" shrink={true}>
{t("Filter")}
</InputLabel>
<Select
labelId="filter-select-label"
id="filter-select"
value={selectedFilter}
label={t("Filter")}
onChange={(e) => setSelectedFilter(e.target.value)}
displayEmpty
>
<MenuItem value="">{t("All")}</MenuItem>
{/* TODO: Add filter options when implementing */}
</Select>
</FormControl>
<Typography variant="body2" sx={{ alignSelf: 'center', color: 'text.secondary' }}>
{t("Auto-refresh every 5 minutes")} | {t("Last updated")}: {isClient && currentTime ? currentTime.format('HH:mm:ss') : '--:--:--'}
{/* Header */}
<Stack direction="row" spacing={2} sx={{ mb: 2 }} alignItems="center" flexWrap="wrap">
<Stack direction="row" spacing={1} alignItems="center">
<Typography variant="body2" sx={{ fontWeight: 600 }}>
{t("Date")}:
</Typography>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DatePicker
value={selectedDate}
onChange={(value) => {
if (!value) return;
setSelectedDate(value);
}}
slotProps={{
textField: {
size: "small",
sx: { minWidth: 160 }
}
}}
/>
</LocalizationProvider>
<Typography variant="caption" color="text.secondary">
{t("Allow to select Date to view history.")}
</Typography>
</Stack>
<Box sx={{ flexGrow: 1 }} />
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
{t("Auto-refresh every 15 minutes")} | {t("Last updated")}: {lastUpdated ? lastUpdated.format('HH:mm:ss') : '--:--:--'}
</Typography>
</Typography>
<Button variant="outlined" color="inherit" onClick={() => setScreenCleared(true)}>
{t("Exit Screen")}
</Button>
</Stack>
</Stack>
{/* Table */}
{/* Table */}
@@ -114,38 +134,80 @@ const GoodsReceiptStatus: React.FC = () => {
<Table size="small" sx={{ minWidth: 1200 }}>
<Table size="small" sx={{ minWidth: 1200 }}>
<TableHead>
<TableHead>
<TableRow sx={{ backgroundColor: 'grey.100' }}>
<TableRow sx={{ backgroundColor: 'grey.100' }}>
<TableCell sx={{ fontWeight: 600 }}>{t("Column 1")}</TableCell>
<TableCell sx={{ fontWeight: 600 }}>{t("Column 2")}</TableCell>
<TableCell sx={{ fontWeight: 600 }}>{t("Column 3")}</TableCell>
{/* TODO: Add table columns when implementing */}
<TableCell sx={{ fontWeight: 600 }}>{t("Supplier")}</TableCell>
<TableCell sx={{ fontWeight: 600 }} align="center">{t("Expected No. of Delivery")}</TableCell>
<TableCell sx={{ fontWeight: 600 }} align="center">{t("No. of Orders Received at Dock")}</TableCell>
<TableCell sx={{ fontWeight: 600 }} align="center">{t("No. of Items Inspected")}</TableCell>
<TableCell sx={{ fontWeight: 600 }} align="center">{t("No. of Items with IQC Issue")}</TableCell>
<TableCell sx={{ fontWeight: 600 }} align="center">{t("No. of Items Completed Put Away at Store")}</TableCell>
</TableRow>
<TableRow sx={{ backgroundColor: 'grey.50' }}>
<TableCell>
<Typography variant="caption" color="text.secondary">
{t("Show Supplier Name")}
</Typography>
</TableCell>
<TableCell align="center">
<Typography variant="caption" color="text.secondary">
{t("Based on Expected Delivery Date")}
</Typography>
</TableCell>
<TableCell align="center">
<Typography variant="caption" color="text.secondary">
{t("Upon entry of DN and Lot No. for all items of the order")}
</Typography>
</TableCell>
<TableCell align="center">
<Typography variant="caption" color="text.secondary">
{t("Upon any IQC decision received")}
</Typography>
</TableCell>
<TableCell align="center">
<Typography variant="caption" color="text.secondary">
{t("Count any item with IQC defect in any IQC criteria")}
</Typography>
</TableCell>
<TableCell align="center">
<Typography variant="caption" color="text.secondary">
{t("Upon completion of put away for an material in order. Count no. of items being put away")}
</Typography>
</TableCell>
</TableRow>
</TableRow>
</TableHead>
</TableHead>
<TableBody>
<TableBody>
{filteredData.length === 0 ? (
{data.length === 0 ? (
<TableRow>
<TableRow>
<TableCell colSpan={3} align="center">
<TableCell colSpan={6 } align="center">
<Typography variant="body2" color="text.secondary">
<Typography variant="body2" color="text.secondary">
{t("No data available")}
{t("No data available")} ({selectedDateLabel})
</Typography>
</Typography>
</TableCell>
</TableCell>
</TableRow>
</TableRow>
) : (
) : (
filteredData.map((row, index) => (
data.map((row, index) => (
<TableRow
<TableRow
key={row.id || index}
key={`${row.supplierId ?? 'na'}-${index}` }
sx={{
sx={{
'&:hover': { backgroundColor: 'grey.50' }
'&:hover': { backgroundColor: 'grey.50' }
}}
}}
>
>
<TableCell>
<TableCell>
{/* TODO: Add table cell content when implementing */}
-
{row.supplierName || '-'}
</TableCell>
</TableCell>
<TableCell>
-
<TableCell align="center" >
{row.expectedNoOfDelivery ?? 0}
</TableCell>
</TableCell>
<TableCell>
-
<TableCell align="center">
{row.noOfOrdersReceivedAtDock ?? 0}
</TableCell>
<TableCell align="center">
{row.noOfItemsInspected ?? 0}
</TableCell>
<TableCell align="center">
{row.noOfItemsWithIqcIssue ?? 0}
</TableCell>
<TableCell align="center">
{row.noOfItemsCompletedPutAwayAtStore ?? 0}
</TableCell>
</TableCell>
</TableRow>
</TableRow>
))
))