// components/BatchInfoWindow.tsx import React, { useEffect, useMemo, useState } from 'react' import { MaterialReactTable, type MRT_ColumnDef, type MRT_PaginationState, type MRT_SortingState, } from 'material-react-table' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faQrcode, faListOl } from '@fortawesome/free-solid-svg-icons' import { NextRouter } from 'next/router' import { StockBatch, StockEntry, Supplier } from '@/types' import axios from 'axios' import { toast } from 'react-hot-toast' import { size } from 'lodash' import {downloadBatchBarcode} from "@/functions/functions" interface Status { id: number name: string } interface BatchInfoWindowProps { selectedBatch: StockBatch | null formatDate?: (value: string, withTime?: boolean) => string router: NextRouter route: (name: string, params: Record) => string /** We now allow `entries` to be null, but internally we coalesce to [] */ entries: StockEntry[] | null /** Any other props you had (for pagination / sorting, etc.) */ entryColumns?: MRT_ColumnDef[] entriesCount?: number entriesLoading?: boolean entriesPagination?: MRT_PaginationState entriesSorting?: MRT_SortingState entriesFilter?: string setEntriesPagination?: (updater: MRT_PaginationState) => void setEntriesSorting?: (sorter: MRT_SortingState) => void setEntriesFilter?: (filter: string) => void openEntry?: (entry: StockEntry) => void recountEnabled?: boolean } const defaultFormatter = (value: string, withTime = true) => { const d = new Date(value) const dd = String(d.getDate()).padStart(2, '0') const mm = String(d.getMonth() + 1).padStart(2, '0') const yyyy = d.getFullYear() if (!withTime) return `${dd}-${mm}-${yyyy}` const hh = String(d.getHours()).padStart(2, '0') const mi = String(d.getMinutes()).padStart(2, '0') return `${dd}-${mm}-${yyyy} ${hh}:${mi}` } const statusIds = [2, 6, 7, 8] export default function BatchInfoWindow({ selectedBatch, formatDate = defaultFormatter, router, route, openEntry, recountEnabled }: BatchInfoWindowProps) { const [statuses, setStatuses] = useState([]) /** Always keep an array here (never null). */ /** Fetch statuses once */ useEffect(() => { console.log(selectedBatch); axios .get('/api/stockStatusList') .then((res) => setStatuses(res.data.statuses)) .catch(() => toast.error('Failed to load status list')) }, []) /** Example helper to calculate ratios */ function calculateStatusRatio(entries: StockEntry[], statusId: number) { const total = entries.length const count = entries.filter((e) => e.status_history?.some((h: any) => h.stock_entries_status_id === statusId) ).length const ratio = total > 0 ? count / total : 0 return { count, total, ratio } } const entryColumnsMemo = useMemo[]>( () => [ { accessorKey: 'id', header: 'ID', size: 80 }, { accessorKey: 'physical_item.name', header: 'Physical Item', size: 200 }, { accessorKey: 'supplier.name', header: 'Supplier', size: 150 }, { accessorKey: 'price', header: 'Price', size: 100, Cell: ({ cell }) => cell.getValue()?.toFixed(2) || '-', }, // …add the rest of your columns here… ], [] ) const hasNonCountedStatus = selectedBatch?.stock_entries?.some((stockEntry) => { const nullSectionStatuses = stockEntry.status_history?.filter((h: any) => h.section_id === null) ?? [] if (nullSectionStatuses.length === 0) return true const latest = nullSectionStatuses.reduce((prev, curr) => new Date(prev.created_at) > new Date(curr.created_at) ? prev : curr ) return latest.stock_entries_status_id !== 2 }) return (
{/* Left: Batch Details & Ratios */}

Batch Details

{selectedBatch ? (
  • ID: {selectedBatch.id}
  • Supplier: {selectedBatch.supplier.name}
  • Tracking #: {selectedBatch.tracking_number}
  • Arrival:{' '} {formatDate(selectedBatch.arrival_date, false)}
) : (

No batch selected.

)} {selectedBatch && (

Status Ratios

{statusIds.map((id) => { const { count, total, ratio } = calculateStatusRatio( selectedBatch.stock_entries, id ) const statusData = statuses.find((s) => s.id === id) return (

{statusData?.name}: {count} / {total} ( {(ratio * 100).toFixed(1)}%)

) })}
)}
{hasNonCountedStatus && selectedBatch && recountEnabled && (
)}
{/* Right: Stock Entries Table (never pass null!) */}

Stock Entries

({ onClick: () => openEntry?.(row.original), style: { cursor: 'pointer' }, })} />
) }