'use client'; import { useEffect, useState } from 'react'; import { useSearchParams } from 'next/navigation'; import { portalAPI, type ExpenseClaim } from '@/lib/api/portal'; import Modal from '@/components/Modal'; function formatDate(value?: string | null) { if (!value) return '-'; const d = new Date(value); if (Number.isNaN(d.getTime())) return value; return d.toLocaleDateString('en-CA'); } function getStatusLabel(status: string) { switch (status) { case 'PENDING': return 'قيد المراجعة'; case 'APPROVED': return 'مقبول'; case 'REJECTED': return 'مرفوض'; default: return status; } } function getStatusClasses(status: string) { switch (status) { case 'PENDING': return 'bg-yellow-100 text-yellow-800'; case 'APPROVED': return 'bg-green-100 text-green-800'; case 'REJECTED': return 'bg-red-100 text-red-800'; default: return 'bg-gray-100 text-gray-700'; } } export default function ManagedExpenseClaimsPage() { const [claims, setClaims] = useState([]); const [loading, setLoading] = useState(true); const [statusFilter, setStatusFilter] = useState('PENDING'); const [submittingId, setSubmittingId] = useState(null); const [rejectModalOpen, setRejectModalOpen] = useState(false); const [selectedClaim, setSelectedClaim] = useState(null); const [rejectReason, setRejectReason] = useState(''); const searchParams = useSearchParams(); const claimId = searchParams.get('claimId'); async function loadClaims(status = statusFilter) { try { setLoading(true); const data = await portalAPI.getManagedExpenseClaims( status === 'all' ? undefined : status ); setClaims(data); } catch (error: any) { alert(error?.response?.data?.message || 'تعذر تحميل طلبات كشف المصاريف'); } finally { setLoading(false); } } useEffect(() => { loadClaims(statusFilter); }, [statusFilter]); async function openAttachment(attachment: any) { try { const blob = await portalAPI.viewExpenseClaimAttachment(attachment.id); const blobUrl = window.URL.createObjectURL( new Blob([blob], { type: attachment.mimeType }) ); window.open(blobUrl, '_blank'); setTimeout(() => { window.URL.revokeObjectURL(blobUrl); }, 10000); } catch (error) { alert('تعذر فتح المرفق'); } } async function handleApprove(id: string) { const note = window.prompt( 'ملاحظة مع الموافقة (اتركها فارغة إذا لا توجد):', '', ); if (note === null) return; try { setSubmittingId(id); await portalAPI.approveManagedExpenseClaim(id, note.trim() || undefined); await loadClaims(statusFilter); } catch (error: any) { alert(error?.response?.data?.message || 'تعذر تنفيذ الموافقة'); } finally { setSubmittingId(null); } } function openRejectModal(claim: ExpenseClaim) { setSelectedClaim(claim); setRejectReason(''); setRejectModalOpen(true); } async function handleRejectSubmit(e: React.FormEvent) { e.preventDefault(); if (!selectedClaim) return; if (!rejectReason.trim()) { alert('سبب الرفض مطلوب'); return; } try { setSubmittingId(selectedClaim.id); await portalAPI.rejectManagedExpenseClaim( selectedClaim.id, rejectReason.trim() ); setRejectModalOpen(false); setSelectedClaim(null); setRejectReason(''); await loadClaims(statusFilter); } catch (error: any) { alert(error?.response?.data?.message || 'تعذر تنفيذ الرفض'); } finally { setSubmittingId(null); } } return (

طلبات كشف المصاريف للقسم

يمكنك مراجعة طلبات كشف المصاريف والموافقة عليها أو رفضها

الطلبات

{loading ? (
جاري التحميل...
) : claims.length === 0 ? (
لا توجد طلبات ضمن هذا الفلتر
) : (
{claims.map((claim) => { const employeeName = claim.employee ? `${claim.employee.firstName} ${claim.employee.lastName}` : '-'; const isBusy = submittingId === claim.id; const isSelected = claim.id === claimId; return (
{claim.claimNumber} {getStatusLabel(claim.status)}
الموظف: {' '} {employeeName}
الرقم الوظيفي: {' '} {claim.employee?.uniqueEmployeeId || '-'}
إجمالي المبلغ: {' '} {claim.totalAmount ?? claim.amount ?? '-'}
تاريخ الإنشاء: {' '} {formatDate(claim.createdAt)}
عدد البنود: {' '} {Array.isArray(claim.items) ? claim.items.length : claim.description ? 1 : 0}
آخر تحديث: {' '} {formatDate(claim.updatedAt)}
{claim.description ? (
ملاحظات عامة: {' '} {claim.description}
) : null} {Array.isArray(claim.items) && claim.items.length > 0 ? (
البنود:
{claim.items.map((item: any, idx: number) => (
التاريخ:{' '} {formatDate(item.expenseDate)}
المبلغ:{' '} {item.amount ?? '-'}
اسم الجهة:{' '} {item.entityName || '-'}
المشروع / المناقصة: {' '} {item.projectOrTender || '-'}
الأوراق المثبتة: {' '} {item.proofRef || '-'}
البيان:{' '} {item.description || '-'}
))}
) : (
تاريخ المصروف:{' '} {formatDate(claim.expenseDate)}
المبلغ:{' '} {claim.amount ?? '-'}
المشروع / المناقصة: {' '} {claim.projectOrTender || '-'}
البيان:{' '} {claim.description || '-'}
)} {claim.attachments && claim.attachments.length > 0 ? (
المرفقات:
{claim.attachments.map((attachment) => ( {attachment.originalName} ))}
) : null} {claim.status === 'REJECTED' && claim.rejectedReason ? (
سبب الرفض:{' '} {claim.rejectedReason}
) : null} {claim.status === 'APPROVED' && claim.approvalNote ? (
ملاحظة المعتمِد:{' '} {claim.approvalNote}
) : null} {claim.status === 'PENDING' ? (
) : null}
); })}
)}
{ setRejectModalOpen(false); setSelectedClaim(null); setRejectReason(''); }} title="رفض طلب كشف المصاريف" >
{selectedClaim ? ( <> سيتم رفض الطلب:{' '} {selectedClaim.claimNumber} ) : null}