/** * Form 16 Quick Actions – RE actions for the Quick Actions sidebar. * Shown only for Form 16 requests when RE user and no credit note yet. * Location: custom (Form 16 only); does not modify shared workflow components. */ import { useState, useEffect } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Loader2, Receipt, X, RotateCcw } from 'lucide-react'; import { getCreditNoteByRequestId, cancelForm16Submission, setForm16ResubmissionNeeded, generateForm16CreditNoteManually, } from '@/services/form16Api'; import { toast } from 'sonner'; interface Form16QuickActionsProps { requestId: string; request: any; onRefresh?: () => void; } export function Form16QuickActions({ requestId, request, onRefresh }: Form16QuickActionsProps) { const [creditNote, setCreditNote] = useState<{ id: number; status: string } | null>(null); const [loading, setLoading] = useState(true); const [actionLoading, setActionLoading] = useState<'cancel' | 'resubmit' | 'credit' | null>(null); const [generateCnOpen, setGenerateCnOpen] = useState(false); const [generateCnAmount, setGenerateCnAmount] = useState(''); const form16 = request?.form16Submission; const hasSubmission = !!form16; const hasCreditNote = !!creditNote && creditNote.status !== 'withdrawn'; const suggestedAmount = form16?.tdsAmount != null ? Number(form16.tdsAmount) : undefined; useEffect(() => { if (!requestId) { setLoading(false); return; } let cancelled = false; (async () => { try { const note = await getCreditNoteByRequestId(requestId); if (!cancelled) setCreditNote(note ? { id: typeof note.id === 'number' ? note.id : Number(note.id), status: note.status || '' } : null); } catch { if (!cancelled) setCreditNote(null); } finally { if (!cancelled) setLoading(false); } })(); return () => { cancelled = true; }; }, [requestId]); const handleCancelSubmission = async () => { if (!requestId || !window.confirm('Cancel this Form 16 submission? The request will be marked as rejected.')) return; setActionLoading('cancel'); try { await cancelForm16Submission(requestId); toast.success('Submission cancelled'); onRefresh?.(); } catch (e) { toast.error(e instanceof Error ? e.message : 'Failed to cancel submission'); } finally { setActionLoading(null); } }; const handleResubmissionNeeded = async () => { if (!requestId || !window.confirm('Mark this submission as resubmission needed? The dealer will need to resubmit Form 16.')) return; setActionLoading('resubmit'); try { await setForm16ResubmissionNeeded(requestId); toast.success('Marked as resubmission needed'); onRefresh?.(); } catch (e) { toast.error(e instanceof Error ? e.message : 'Failed to update'); } finally { setActionLoading(null); } }; const handleGenerateCreditNote = async () => { const amount = parseFloat(generateCnAmount); if (!requestId || Number.isNaN(amount) || amount <= 0) { toast.error('Enter a valid amount to generate credit note'); return; } setActionLoading('credit'); try { await generateForm16CreditNoteManually(requestId, amount); setGenerateCnOpen(false); setGenerateCnAmount(''); toast.success('Credit note generated (manually approved)'); const note = await getCreditNoteByRequestId(requestId); setCreditNote(note ? { id: typeof note.id === 'number' ? note.id : Number(note.id), status: note.status || '' } : null); onRefresh?.(); } catch (e) { toast.error(e instanceof Error ? e.message : 'Failed to generate credit note'); } finally { setActionLoading(null); } }; if (loading || !hasSubmission || hasCreditNote) return null; return ( <> Form 16 actions View the document in the Documents tab. Cancel submission, mark resubmission needed, or generate credit note (e.g. when OCR was partial). {actionLoading === 'cancel' ? : } Cancel submission {actionLoading === 'resubmit' ? : } Resubmission needed { setGenerateCnAmount(suggestedAmount != null ? String(suggestedAmount) : ''); setGenerateCnOpen(true); }} disabled={!!actionLoading} > {actionLoading === 'credit' ? : } Generate credit note Generate credit note (manual) Enter the amount for the credit note. This will mark the Form 16 as manually approved. Amount (₹) setGenerateCnAmount(e.target.value)} /> {suggestedAmount != null && ( Suggested from submission TDS amount: ₹{suggestedAmount.toLocaleString('en-IN')} )} setGenerateCnOpen(false)} disabled={!!actionLoading}> Cancel {actionLoading === 'credit' ? : null} Generate credit note > ); }
Suggested from submission TDS amount: ₹{suggestedAmount.toLocaleString('en-IN')}