import React, { useState, useMemo } from 'react'; import { format } from 'date-fns'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { CheckCircle, XCircle, Search, User, Package, Loader2, ChevronDown, ChevronUp, AlertTriangle, } from 'lucide-react'; import { AssetRequestWithAvailability, AssetRequestApprovalRequest, AssetRequestRejectionRequest, } from '@/types/asset-request'; import ActionDialog from './ActionDialog'; import ViewDetailsDialog from './ViewDetailsDialog'; import CommentDialog from './CommentDialog'; interface AssetRequestReviewProps { requests: AssetRequestWithAvailability[]; isLoading?: boolean; onApprove: (id: number, data: AssetRequestApprovalRequest) => Promise; onReject: (id: number, data: AssetRequestRejectionRequest) => Promise; onAddComment?: (id: number, comments: string) => Promise; currentUserId: number; } type SortField = 'date' | 'employee' | 'assetType'; type SortOrder = 'asc' | 'desc'; const AssetRequestReview: React.FC = ({ requests, isLoading = false, onApprove, onReject, onAddComment, currentUserId, }) => { const [searchTerm, setSearchTerm] = useState(''); const [sortField, setSortField] = useState('date'); const [sortOrder, setSortOrder] = useState('desc'); const [selectedRequest, setSelectedRequest] = useState(null); const [showDetailDialog, setShowDetailDialog] = useState(false); const [showApproveDialog, setShowApproveDialog] = useState(false); const [showRejectDialog, setShowRejectDialog] = useState(false); const [showCommentDialog, setShowCommentDialog] = useState(false); // Filter and sort requests const filteredAndSortedRequests = useMemo(() => { let filtered = [...requests]; // Apply search filter if (searchTerm) { const term = searchTerm.toLowerCase(); filtered = filtered.filter( (req) => req.requestID.toString().includes(term) || req.employeeName.toLowerCase().includes(term) || req.justification.toLowerCase().includes(term) || req.requestedAssets.some((asset) => asset.assetType.toLowerCase().includes(term) ) ); } // Apply sorting filtered.sort((a, b) => { let comparison = 0; switch (sortField) { case 'date': comparison = new Date(a.submittedDate).getTime() - new Date(b.submittedDate).getTime(); break; case 'employee': comparison = a.employeeName.localeCompare(b.employeeName); break; case 'assetType': const aTypes = a.requestedAssets.map((asset) => asset.assetType).join(', '); const bTypes = b.requestedAssets.map((asset) => asset.assetType).join(', '); comparison = aTypes.localeCompare(bTypes); break; } return sortOrder === 'asc' ? comparison : -comparison; }); return filtered; }, [requests, searchTerm, sortField, sortOrder]); const handleSort = (field: SortField) => { if (sortField === field) { setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc'); } else { setSortField(field); setSortOrder('asc'); } }; const handleViewDetails = (request: AssetRequestWithAvailability) => { setSelectedRequest(request); setShowDetailDialog(true); }; const handleApproveClick = (request: AssetRequestWithAvailability) => { setSelectedRequest(request); // Use setTimeout to ensure state is set before opening dialog setTimeout(() => setShowApproveDialog(true), 0); }; const handleRejectClick = (request: AssetRequestWithAvailability) => { setSelectedRequest(request); // Use setTimeout to ensure state is set before opening dialog setTimeout(() => setShowRejectDialog(true), 0); }; const handleAddCommentClick = (request: AssetRequestWithAvailability) => { setSelectedRequest(request); setTimeout(() => setShowCommentDialog(true), 0); }; const handleApproveConfirm = async (comments: string) => { if (!selectedRequest) return; await onApprove(selectedRequest.requestID, { adminComments: comments, reviewedBy: currentUserId, }); }; const handleRejectConfirm = async (comments: string) => { if (!selectedRequest) return; await onReject(selectedRequest.requestID, { adminComments: comments, reviewedBy: currentUserId, }); }; const handleCommentConfirm = async (comments: string) => { if (!selectedRequest || !onAddComment) return; await onAddComment(selectedRequest.requestID, comments); }; const handleApproveDialogClose = () => { setShowApproveDialog(false); setSelectedRequest(null); }; const handleRejectDialogClose = () => { setShowRejectDialog(false); setSelectedRequest(null); }; const handleCommentDialogClose = () => { setShowCommentDialog(false); setSelectedRequest(null); }; const getAvailabilityBadge = (available: number, requested: number, showWarning: boolean = false) => { if (available >= requested) { return (
Available ({available}) {showWarning && available < requested * 2 && (
Low stock warning
)}
); } else if (available > 0) { return ( Partial ({available}/{requested}) ); } else { return ( Unavailable ); } }; const SortIcon: React.FC<{ field: SortField }> = ({ field }) => { if (sortField !== field) return null; return sortOrder === 'asc' ? ( ) : ( ); }; if (isLoading) { return ( ); } return (
{/* Search and Sort Controls */} Pending Asset Requests
setSearchTerm(e.target.value)} className="pl-10" />
{/* Requests Table */} {filteredAndSortedRequests.length === 0 ? (

{searchTerm ? 'No requests match your search criteria' : 'No pending asset requests'}

) : (
handleSort('date')} > Date handleSort('employee')} > Employee handleSort('assetType')} > Assets Availability Actions {filteredAndSortedRequests.map((request) => (
#{request.requestID} {format(new Date(request.submittedDate), 'MMM dd, yyyy')}
{request.employeeName}
{request.requestedAssets.map((asset, idx) => (
{asset.assetType} (x{asset.quantity})
))}
{request.availabilityStatus.map((status, idx) => (
{getAvailabilityBadge(status.available, status.requested, true)}
))}
))}
)} {/* View Details Dialog */} setShowDetailDialog(false)} request={selectedRequest} onApprove={handleApproveClick} onReject={handleRejectClick} onAddComment={onAddComment ? handleAddCommentClick : undefined} /> {/* Approve Dialog */} {selectedRequest && ( )} {/* Reject Dialog */} {selectedRequest && ( )} {/* Comment Dialog */} {selectedRequest && onAddComment && ( )}
); }; export default AssetRequestReview;