263 lines
8.6 KiB
TypeScript
263 lines
8.6 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useState } from 'react';
|
||
|
|
import type { CoilUsageRow } from '@/types/coil-activity';
|
||
|
|
import {
|
||
|
|
Card,
|
||
|
|
CardContent,
|
||
|
|
CardDescription,
|
||
|
|
CardHeader,
|
||
|
|
CardTitle,
|
||
|
|
} from '@/components/ui/card';
|
||
|
|
import { Input } from '@/components/ui/input';
|
||
|
|
import { Button } from '@/components/ui/button';
|
||
|
|
import {
|
||
|
|
Table,
|
||
|
|
TableBody,
|
||
|
|
TableCell,
|
||
|
|
TableRow,
|
||
|
|
} from '@/components/ui/table';
|
||
|
|
import { Download, Search } from 'lucide-react';
|
||
|
|
import {
|
||
|
|
SortableTableHead,
|
||
|
|
useSortableTable,
|
||
|
|
} from '@/components/ui/sortable-table-head';
|
||
|
|
import { formatDate } from '@/lib/utils';
|
||
|
|
|
||
|
|
type Props = {
|
||
|
|
data: CoilUsageRow[];
|
||
|
|
};
|
||
|
|
|
||
|
|
export function UsageTable({ data }: Props) {
|
||
|
|
const [searchTerm, setSearchTerm] = useState('');
|
||
|
|
|
||
|
|
const filteredData = data.filter((row) => {
|
||
|
|
const s = searchTerm.toLowerCase();
|
||
|
|
return (
|
||
|
|
(row.vorteq_part_num || '').toLowerCase().includes(s) ||
|
||
|
|
(row.customer_part_num || '').toLowerCase().includes(s) ||
|
||
|
|
(row.part_desc || '').toLowerCase().includes(s) ||
|
||
|
|
(row.lot_num || '').toLowerCase().includes(s) ||
|
||
|
|
(row.mfg_lot || '').toLowerCase().includes(s) ||
|
||
|
|
(row.plant_name || '').toLowerCase().includes(s) ||
|
||
|
|
(row.job_num || '').toLowerCase().includes(s) ||
|
||
|
|
(row.customer_po || '').toLowerCase().includes(s)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
const { sortKey, sortDirection, handleSort, sortedData } =
|
||
|
|
useSortableTable(filteredData);
|
||
|
|
|
||
|
|
const handleExportCSV = () => {
|
||
|
|
const headers = [
|
||
|
|
'Date Used',
|
||
|
|
'Vorteq Part#',
|
||
|
|
'Cust Part#',
|
||
|
|
'Part Description',
|
||
|
|
'Lot#',
|
||
|
|
'Mfg Lot#',
|
||
|
|
'Weight',
|
||
|
|
'Plant Name',
|
||
|
|
'Job#',
|
||
|
|
'Cust PO#',
|
||
|
|
'Qty LB',
|
||
|
|
];
|
||
|
|
|
||
|
|
const rows = sortedData.map((row) => [
|
||
|
|
row.date_used ? new Date(row.date_used).toLocaleDateString() : '',
|
||
|
|
row.vorteq_part_num || '',
|
||
|
|
row.customer_part_num || '',
|
||
|
|
row.part_desc || '',
|
||
|
|
row.lot_num || '',
|
||
|
|
row.mfg_lot || '',
|
||
|
|
row.weight ?? '',
|
||
|
|
row.plant_name || '',
|
||
|
|
row.job_num || '',
|
||
|
|
row.customer_po || '',
|
||
|
|
row.on_hand_qty ?? '',
|
||
|
|
]);
|
||
|
|
|
||
|
|
const csvContent = [headers, ...rows]
|
||
|
|
.map((row) => row.map((cell) => `"${cell}"`).join(','))
|
||
|
|
.join('\n');
|
||
|
|
|
||
|
|
const blob = new Blob([csvContent], { type: 'text/csv' });
|
||
|
|
const url = window.URL.createObjectURL(blob);
|
||
|
|
const a = document.createElement('a');
|
||
|
|
a.href = url;
|
||
|
|
a.download = `usage-data-${new Date().toISOString().split('T')[0]}.csv`;
|
||
|
|
a.click();
|
||
|
|
window.URL.revokeObjectURL(url);
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Card>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle>Usage Data</CardTitle>
|
||
|
|
<CardDescription>Showing {sortedData.length} results</CardDescription>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent>
|
||
|
|
<div className="mb-4 flex items-center gap-4">
|
||
|
|
<div className="relative flex-1">
|
||
|
|
<Search className="absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
||
|
|
<Input
|
||
|
|
placeholder="Search part numbers, descriptions, lots, plants, jobs..."
|
||
|
|
value={searchTerm}
|
||
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||
|
|
className="pl-8"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
<Button onClick={handleExportCSV} variant="outline">
|
||
|
|
<Download className="mr-2 h-4 w-4" />
|
||
|
|
Export CSV
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="overflow-hidden rounded-md border">
|
||
|
|
<Table>
|
||
|
|
<thead>
|
||
|
|
<tr className="bg-teal-700 text-white">
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="date_used"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
>
|
||
|
|
Date Used
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="vorteq_part_num"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
>
|
||
|
|
Vorteq Part#
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="customer_part_num"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
>
|
||
|
|
Cust Part#
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="part_desc"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
>
|
||
|
|
Part Description
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="lot_num"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
>
|
||
|
|
Lot#
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="mfg_lot"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
>
|
||
|
|
Mfg Lot#
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="weight"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
className="text-right"
|
||
|
|
>
|
||
|
|
Weight
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="plant_name"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
>
|
||
|
|
Plant Name
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="job_num"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
>
|
||
|
|
Job#
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="customer_po"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
>
|
||
|
|
Cust PO#
|
||
|
|
</SortableTableHead>
|
||
|
|
<SortableTableHead
|
||
|
|
sortKey="on_hand_qty"
|
||
|
|
currentSortKey={sortKey}
|
||
|
|
currentDirection={sortDirection}
|
||
|
|
onSort={handleSort}
|
||
|
|
className="text-right"
|
||
|
|
>
|
||
|
|
Qty LB
|
||
|
|
</SortableTableHead>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<TableBody>
|
||
|
|
{sortedData.length === 0 ? (
|
||
|
|
<TableRow>
|
||
|
|
<TableCell
|
||
|
|
colSpan={11}
|
||
|
|
className="text-center text-muted-foreground"
|
||
|
|
>
|
||
|
|
No usage data found
|
||
|
|
</TableCell>
|
||
|
|
</TableRow>
|
||
|
|
) : (
|
||
|
|
sortedData.map((row, i) => (
|
||
|
|
<TableRow
|
||
|
|
key={i}
|
||
|
|
className={i % 2 === 0 ? 'bg-muted/30' : ''}
|
||
|
|
>
|
||
|
|
<TableCell>
|
||
|
|
{row.date_used ? formatDate(new Date(row.date_used)) : '-'}
|
||
|
|
</TableCell>
|
||
|
|
<TableCell>{row.vorteq_part_num || '-'}</TableCell>
|
||
|
|
<TableCell>{row.customer_part_num || '-'}</TableCell>
|
||
|
|
<TableCell>{row.part_desc || '-'}</TableCell>
|
||
|
|
<TableCell>{row.lot_num || '-'}</TableCell>
|
||
|
|
<TableCell>{row.mfg_lot || '-'}</TableCell>
|
||
|
|
<TableCell className="text-right">
|
||
|
|
{row.weight != null
|
||
|
|
? row.weight.toLocaleString()
|
||
|
|
: '-'}
|
||
|
|
</TableCell>
|
||
|
|
<TableCell>{row.plant_name || '-'}</TableCell>
|
||
|
|
<TableCell>{row.job_num || '-'}</TableCell>
|
||
|
|
<TableCell>{row.customer_po || '-'}</TableCell>
|
||
|
|
<TableCell className="text-right">
|
||
|
|
{row.on_hand_qty != null
|
||
|
|
? row.on_hand_qty.toLocaleString()
|
||
|
|
: '-'}
|
||
|
|
</TableCell>
|
||
|
|
</TableRow>
|
||
|
|
))
|
||
|
|
)}
|
||
|
|
</TableBody>
|
||
|
|
</Table>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="mt-4 text-sm text-muted-foreground">
|
||
|
|
Showing {sortedData.length} of {data.length} records
|
||
|
|
</div>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
}
|