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 { Card, CardContent } from '@/components/ui/card'; import { CustomDropdown } from './shared/CustomDropdown'; import { Badge } from '@/components/ui/badge'; import { Search, Eye, Edit, Trash2, Plus, ArrowUpDown, ArrowUp, ArrowDown, User, Calendar, CheckCircle, Clock } from 'lucide-react'; import { AssetAssignment, AssetAssignmentWithDetails } from '@/types/asset-management'; import { format, isValid, subDays, subMonths, subYears } from 'date-fns'; import { LoadingSpinner } from './shared'; import Pagination from './shared/Pagination'; import { usePagination } from '@/hooks/asset-management/usePagination'; import { useIsMobile } from '@/hooks/use-mobile'; interface AssignmentListProps { assignments: AssetAssignment[] | AssetAssignmentWithDetails[]; isLoading?: boolean; onView?: (assignment: AssetAssignment) => void; onEdit?: (assignment: AssetAssignment) => void; onDelete?: (assignment: AssetAssignment) => void; onCreate?: () => void; onNavigateToAsset?: (assetId: number) => void; onNavigateToEmployee?: (employeeId: number) => void; showActions?: boolean; showAssetInfo?: boolean; } type SortField = keyof AssetAssignment; type SortDirection = 'asc' | 'desc'; interface SortConfig { field: SortField; direction: SortDirection; } const AssignmentList: React.FC = ({ assignments, isLoading = false, onView, onEdit, onDelete, onCreate, onNavigateToAsset, onNavigateToEmployee, showActions = true, showAssetInfo = true }) => { const isMobile = useIsMobile(); const [searchTerm, setSearchTerm] = useState(''); const [statusFilter, setStatusFilter] = useState('all'); const [dateRangeFilter, setDateRangeFilter] = useState('all'); const [sortConfig, setSortConfig] = useState({ field: 'assignmentID', direction: 'desc' }); // Helper function to determine assignment status const getAssignmentStatus = (assignment: AssetAssignment) => { return assignment.returnedDate ? 'returned' : 'active'; }; // Helper function to get status badge variant const getStatusBadgeVariant = (status: string) => { switch (status) { case 'active': return 'default'; case 'returned': return 'secondary'; default: return 'outline'; } }; // Helper function to format date safely const formatDate = (dateString: string | null) => { if (!dateString) return 'N/A'; const date = new Date(dateString); return isValid(date) ? format(date, 'PP') : 'Invalid Date'; }; // Helper function to check if assignment matches date range filter const matchesDateRange = (assignment: AssetAssignment) => { if (dateRangeFilter === 'all') return true; const assignedDate = new Date(assignment.assignedDate); const now = new Date(); switch (dateRangeFilter) { case 'last7days': return assignedDate >= subDays(now, 7); case 'last30days': return assignedDate >= subDays(now, 30); case 'last3months': return assignedDate >= subMonths(now, 3); case 'lastyear': return assignedDate >= subYears(now, 1); default: return true; } }; // Filter and sort assignments const filteredAndSortedAssignments = useMemo(() => { let filtered = assignments.filter(assignment => { const assignmentWithDetails = assignment as AssetAssignmentWithDetails; const status = getAssignmentStatus(assignment); const matchesSearch = assignment.employeeID.toString().includes(searchTerm) || assignment.assetID.toString().includes(searchTerm) || (assignment.assetCode && assignment.assetCode.toLowerCase().includes(searchTerm.toLowerCase())) || assignment.remarks.toLowerCase().includes(searchTerm.toLowerCase()) || (assignment.employeeName && assignment.employeeName.toLowerCase().includes(searchTerm.toLowerCase())) || (assignmentWithDetails.asset && (assignmentWithDetails.asset.assetCode.toLowerCase().includes(searchTerm.toLowerCase()) || assignmentWithDetails.asset.assetType.toLowerCase().includes(searchTerm.toLowerCase()) || assignmentWithDetails.asset.brandModel.toLowerCase().includes(searchTerm.toLowerCase()) || assignmentWithDetails.asset.serialNumber.toLowerCase().includes(searchTerm.toLowerCase()))); const matchesStatus = statusFilter === 'all' || status === statusFilter; const matchesDateRangeFilter = matchesDateRange(assignment); return matchesSearch && matchesStatus && matchesDateRangeFilter; }); // Sort assignments 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; } // Handle date sorting if (sortConfig.field === 'assignedDate' || sortConfig.field === 'returnedDate') { const aDate = new Date(aValue as string); const bDate = new Date(bValue as string); const comparison = aDate.getTime() - bDate.getTime(); return sortConfig.direction === 'asc' ? comparison : -comparison; } return 0; }); return filtered; }, [assignments, searchTerm, statusFilter, dateRangeFilter, sortConfig]); // Use pagination hook const { currentPage, itemsPerPage, totalPages, paginatedData: paginatedAssignments, setCurrentPage, setItemsPerPage, } = usePagination(filteredAndSortedAssignments); 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' ? : ; }; // Mobile Card Component const AssignmentCard: React.FC<{ assignment: AssetAssignment }> = ({ assignment }) => { const assignmentWithDetails = assignment as AssetAssignmentWithDetails; const status = getAssignmentStatus(assignment); return (
ID #{assignment.assignmentID} {status === 'active' ? ( <> Active ) : ( <> Returned )}
{showActions && (
{onView && ( )} {onEdit && ( )} {onDelete && ( )}
)}
{/* Employee Info */}
{assignment.employeeName || `Employee #${assignment.employeeID}`}
{assignmentWithDetails.employeeEmail && (
{assignmentWithDetails.employeeEmail}
)}
{/* Asset Info */} {showAssetInfo && (
{assignment.assetCode || `Asset #${assignment.assetID}`}
{assignmentWithDetails.asset ? ( <>
{assignmentWithDetails.asset.assetType}
{assignmentWithDetails.asset.brandModel}
) : (
{assignment.assetCode}
)}
)} {/* Dates */}
Assigned: {formatDate(assignment.assignedDate)}
{assignment.returnedDate && (
Returned: {formatDate(assignment.returnedDate)}
)}
{/* Remarks */} {assignment.remarks && (
Remarks: {assignment.remarks}
)}
); }; if (isLoading) { return (

Asset Assignments

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

Asset Assignments

{onCreate && ( )}
{/* Filters */}
setSearchTerm(e.target.value)} className="pl-10" />
{/* Results count */}
Showing {paginatedAssignments.length} of {filteredAndSortedAssignments.length} assignments {filteredAndSortedAssignments.length !== assignments.length && ( (filtered from {assignments.length} total) )}
{/* Mobile Card View / Desktop Table View */} {isMobile ? ( // Mobile Card Layout
{paginatedAssignments.length === 0 ? ( {assignments.length === 0 ? "No assignments found. Create your first assignment to get started." : "No assignments match your current filters." } ) : ( paginatedAssignments.map((assignment) => ( )) )}
) : ( // Desktop Table Layout
handleSort('assignmentID')} >
ID {getSortIcon('assignmentID')}
{showAssetInfo && ( handleSort('assetCode')} >
Asset {getSortIcon('assetCode')}
)} handleSort('employeeID')} >
Employee {getSortIcon('employeeID')}
handleSort('assignedDate')} >
Assigned Date {getSortIcon('assignedDate')}
handleSort('returnedDate')} >
Returned Date {getSortIcon('returnedDate')}
Status Remarks {showActions && Actions}
{paginatedAssignments.length === 0 ? ( {assignments.length === 0 ? "No assignments found. Create your first assignment to get started." : "No assignments match your current filters." } ) : ( paginatedAssignments.map((assignment) => { const assignmentWithDetails = assignment as AssetAssignmentWithDetails; const status = getAssignmentStatus(assignment); return ( {assignment.assignmentID} {showAssetInfo && (
{/* {assignment.assetCode || `#${assignment.assetID}`} */} {assignmentWithDetails.asset ? (
{assignmentWithDetails.asset.assetType}
{assignmentWithDetails.asset.brandModel}
) : (
{assignment.assetCode}
)}
)}
{assignment.employeeName || `Employee #${assignment.employeeID}`}
{assignmentWithDetails.employeeEmail && (
{assignmentWithDetails.employeeEmail}
)}
{formatDate(assignment.assignedDate)}
{assignment.returnedDate ? (
{formatDate(assignment.returnedDate)}
) : ( - )}
{status === 'active' ? ( <> Active ) : ( <> Returned )} {assignment.remarks} {showActions && (
{onView && ( )} {onEdit && ( )} {onDelete && ( )}
)}
); }) )}
)} {/* Pagination */} {filteredAndSortedAssignments.length > 0 && ( )}
); }; export default AssignmentList;