/** * DeptLeadIOApprovalModal Component * Modal for Step 3: Dept Lead Approval and IO Organization * Allows department lead to approve request and organize IO details */ import { useState, useMemo } from 'react'; import * as React from 'react'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Badge } from '@/components/ui/badge'; import { CircleCheckBig, CircleX, Receipt, TriangleAlert } from 'lucide-react'; import { toast } from 'sonner'; interface DeptLeadIOApprovalModalProps { isOpen: boolean; onClose: () => void; onApprove: (data: { ioNumber: string; ioRemark: string; comments: string; }) => Promise; onReject: (comments: string) => Promise; requestTitle?: string; requestId?: string; // Pre-filled IO data from IO table preFilledIONumber?: string; preFilledIORemark?: string; preFilledBlockedAmount?: number; preFilledRemainingBalance?: number; } export function DeptLeadIOApprovalModal({ isOpen, onClose, onApprove, onReject, requestTitle, requestId: _requestId, preFilledIONumber, preFilledIORemark, preFilledBlockedAmount, preFilledRemainingBalance, }: DeptLeadIOApprovalModalProps) { const [actionType, setActionType] = useState<'approve' | 'reject'>('approve'); const [ioRemark, setIoRemark] = useState(''); const [comments, setComments] = useState(''); const [submitting, setSubmitting] = useState(false); // Get IO number from props (read-only, from IO table) const ioNumber = preFilledIONumber || ''; // Reset form when modal opens/closes React.useEffect(() => { if (isOpen) { // Prefill IO remark from props if available setIoRemark(preFilledIORemark || ''); setComments(''); setActionType('approve'); } }, [isOpen, preFilledIORemark]); const ioRemarkChars = ioRemark.length; const commentsChars = comments.length; const maxIoRemarkChars = 300; const maxCommentsChars = 500; // Validate form const isFormValid = useMemo(() => { if (actionType === 'reject') { return comments.trim().length > 0; } // For approve, need IO number (from table), IO remark, and comments return ( ioNumber.trim().length > 0 && // IO number must exist from IO table ioRemark.trim().length > 0 && comments.trim().length > 0 ); }, [actionType, ioNumber, ioRemark, comments]); const handleSubmit = async () => { if (!isFormValid) { if (actionType === 'approve') { if (!ioNumber.trim()) { toast.error('IO number is required. Please block amount from IO tab first.'); return; } if (!ioRemark.trim()) { toast.error('Please enter IO remark'); return; } } if (!comments.trim()) { toast.error('Please provide comments'); return; } return; } try { setSubmitting(true); if (actionType === 'approve') { await onApprove({ ioNumber: ioNumber.trim(), ioRemark: ioRemark.trim(), comments: comments.trim(), }); } else { await onReject(comments.trim()); } handleReset(); onClose(); } catch (error) { console.error(`Failed to ${actionType} request:`, error); toast.error(`Failed to ${actionType} request. Please try again.`); } finally { setSubmitting(false); } }; const handleReset = () => { setActionType('approve'); setIoRemark(''); setComments(''); }; const handleClose = () => { if (!submitting) { handleReset(); onClose(); } }; return (
Approve and Organise IO Review IO details and provide your approval comments
{/* Request Info Card */}
Workflow Step: Step 3
Title:

{requestTitle || '—'}

Action: APPROVE
{/* Action Toggle Buttons */}
{/* IO Organisation Details - Only shown when approving */} {actionType === 'approve' && (

IO Organisation Details

{/* IO Number - Read-only from IO table */}
{!ioNumber && (

⚠️ IO number not found. Please block amount from IO tab first.

)} {ioNumber && (

✓ Loaded from IO table

)}
{/* IO Balance Information - Read-only */}
{/* Blocked Amount Display */} {preFilledBlockedAmount !== undefined && preFilledBlockedAmount > 0 && (
Blocked Amount: ₹{preFilledBlockedAmount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
)} {/* Remaining Balance Display */} {preFilledRemainingBalance !== undefined && preFilledRemainingBalance !== null && (
Remaining Balance: ₹{preFilledRemainingBalance.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
)}
{/* IO Remark - Editable field (prefilled from IO tab, but can be modified) */}