import React, { useState, useMemo } from 'react'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { CustomDropdown } from './shared/CustomDropdown'; import { Badge } from '@/components/ui/badge'; import { Search, Eye, Edit, Trash2, Plus, ArrowUpDown, ArrowUp, ArrowDown, Grid3X3, List, UserPlus, User } from 'lucide-react'; import { Asset, AssetCondition, ASSET_CONDITIONS, ASSET_TYPES, AssetAssignment } from '@/types/asset-management'; import { LoadingSpinner } from './shared'; import Pagination from './shared/Pagination'; import AssetCard from './shared/AssetCard'; import { usePagination } from '@/hooks/asset-management/usePagination'; interface AssetListProps { assets: Asset[]; assignments?: AssetAssignment[]; isLoading?: boolean; onView?: (asset: Asset) => void; onEdit?: (asset: Asset) => void; onDelete?: (asset: Asset) => void; onCreate?: () => void; onAssign?: (asset: Asset) => void; showActions?: boolean; } type SortField = keyof Asset; type SortDirection = 'asc' | 'desc'; interface SortConfig { field: SortField; direction: SortDirection; } const AssetList: React.FC = ({ assets, assignments = [], isLoading = false, onView, onEdit, onDelete, onCreate, onAssign, showActions = true }) => { const [searchTerm, setSearchTerm] = useState(''); const [typeFilter, setTypeFilter] = useState('all'); const [conditionFilter, setConditionFilter] = useState('all'); const [assignmentStatusFilter, setAssignmentStatusFilter] = useState('all'); const [sortConfig, setSortConfig] = useState({ field: 'assetCode', direction: 'asc' }); const [viewMode, setViewMode] = useState<'table' | 'cards'>('table'); // Helper function to get badge variant based on asset condition const getConditionBadgeVariant = (condition: AssetCondition) => { switch (condition) { case 'Excellent': return 'default'; case 'Good': return 'secondary'; case 'Fair': return 'outline'; case 'Poor': return 'destructive'; default: return 'outline'; } }; // Helper function to get active assignment for an asset const getActiveAssignment = (assetId: number): AssetAssignment | undefined => { return assignments.find( assignment => assignment.assetID === assetId && !assignment.returnedDate ); }; // Helper function to check if asset is available for assignment const isAssetAvailable = (assetId: number): boolean => { return !getActiveAssignment(assetId); }; // Helper function to get assignment status for an asset const getAssetAssignmentStatus = (assetId: number) => { return getActiveAssignment(assetId) ? 'assigned' : 'unassigned'; }; // Filter and sort assets const filteredAndSortedAssets = useMemo(() => { let filtered = assets.filter(asset => { const matchesSearch = asset.assetType.toLowerCase().includes(searchTerm.toLowerCase()) || asset.brandModel.toLowerCase().includes(searchTerm.toLowerCase()) || asset.serialNumber.toLowerCase().includes(searchTerm.toLowerCase()) || asset.assetCode.toLowerCase().includes(searchTerm.toLowerCase()); const matchesType = typeFilter === 'all' || asset.assetType === typeFilter; const matchesCondition = conditionFilter === 'all' || asset.assetCondition === conditionFilter; const assetAssignmentStatus = getAssetAssignmentStatus(asset.assetID); const matchesAssignmentStatus = assignmentStatusFilter === 'all' || assetAssignmentStatus === assignmentStatusFilter; return matchesSearch && matchesType && matchesCondition && matchesAssignmentStatus; }); // Sort assets filtered.sort((a, b) => { const aValue = a[sortConfig.field]; const bValue = b[sortConfig.field]; if (typeof aValue === 'string' && typeof bValue === 'string') { const comparison = aValue.localeCompare(bValue); return sortConfig.direction === 'asc' ? comparison : -comparison; } if (typeof aValue === 'number' && typeof bValue === 'number') { const comparison = aValue - bValue; return sortConfig.direction === 'asc' ? comparison : -comparison; } return 0; }); return filtered; }, [assets, assignments, searchTerm, typeFilter, conditionFilter, assignmentStatusFilter, sortConfig]); // Use pagination hook const { currentPage, itemsPerPage, totalPages, paginatedData: paginatedAssets, setCurrentPage, setItemsPerPage, } = usePagination(filteredAndSortedAssets); const handleSort = (field: SortField) => { setSortConfig(prev => ({ field, direction: prev.field === field && prev.direction === 'asc' ? 'desc' : 'asc' })); }; const getSortIcon = (field: SortField) => { if (sortConfig.field !== field) { return ; } return sortConfig.direction === 'asc' ? : ; }; if (isLoading) { return (

Assets

); } return (
{/* Header */}

Assets

{/* View Mode Toggle */}
{onCreate && ( )}
{/* Filters */}
({ value: type, label: type })) ]} value={typeFilter} onChange={setTypeFilter} placeholder="Filter by type" className="w-full" aria-label="Filter by asset type" />
({ value: condition, label: condition })) ]} value={conditionFilter} onChange={setConditionFilter} placeholder="Filter by condition" className="w-full" aria-label="Filter by asset condition" />
{/* Results count */}
Showing {paginatedAssets.length} of {filteredAndSortedAssets.length} assets {filteredAndSortedAssets.length !== assets.length && ( (filtered from {assets.length} total) )}
{/* Table View - Desktop */} {viewMode === 'table' && (
handleSort('assetCode')} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleSort('assetCode'); } }} tabIndex={0} role="button" aria-label={`Sort by Code ${sortConfig.field === 'assetCode' ? (sortConfig.direction === 'asc' ? 'descending' : 'ascending') : 'ascending'}`} >
Code {getSortIcon('assetCode')}
handleSort('assetType')} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleSort('assetType'); } }} tabIndex={0} role="button" aria-label={`Sort by Type ${sortConfig.field === 'assetType' ? (sortConfig.direction === 'asc' ? 'descending' : 'ascending') : 'ascending'}`} >
Type {getSortIcon('assetType')}
handleSort('brandModel')} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleSort('brandModel'); } }} tabIndex={0} role="button" aria-label={`Sort by Brand/Model ${sortConfig.field === 'brandModel' ? (sortConfig.direction === 'asc' ? 'descending' : 'ascending') : 'ascending'}`} >
Brand/Model {getSortIcon('brandModel')}
handleSort('serialNumber')} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleSort('serialNumber'); } }} tabIndex={0} role="button" aria-label={`Sort by Serial Number ${sortConfig.field === 'serialNumber' ? (sortConfig.direction === 'asc' ? 'descending' : 'ascending') : 'ascending'}`} >
Serial Number {getSortIcon('serialNumber')}
handleSort('assetCondition')} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleSort('assetCondition'); } }} tabIndex={0} role="button" aria-label={`Sort by Condition ${sortConfig.field === 'assetCondition' ? (sortConfig.direction === 'asc' ? 'descending' : 'ascending') : 'ascending'}`} >
Condition {getSortIcon('assetCondition')}
Status {showActions && Actions}
{paginatedAssets.length === 0 ? ( {assets.length === 0 ? "No assets found. Create your first asset to get started." : "No assets match your current filters." } ) : ( paginatedAssets.map((asset) => { const activeAssignment = getActiveAssignment(asset.assetID); const isAvailable = isAssetAvailable(asset.assetID); return ( {asset.assetCode} {asset.assetType} {asset.brandModel} {asset.serialNumber} {asset.assetCondition} {activeAssignment ? ( Assigned to {activeAssignment.employeeName} ) : ( Available )} {showActions && (
{onAssign && isAvailable && ( )} {onView && ( )} {onEdit && ( )} {onDelete && ( )}
)}
); }) )}
)} {/* Card View - Desktop */} {viewMode === 'cards' && (
{paginatedAssets.length === 0 ? (
{assets.length === 0 ? "No assets found. Create your first asset to get started." : "No assets match your current filters." }
) : (
{paginatedAssets.map((asset) => ( ))}
)}
)} {/* Mobile Card View */}
{paginatedAssets.length === 0 ? (
{assets.length === 0 ? "No assets found. Create your first asset to get started." : "No assets match your current filters." }
) : ( paginatedAssets.map((asset) => ( )) )}
{/* Pagination */} {filteredAndSortedAssets.length > 0 && ( )}
); }; export default AssetList;