Re_Figma_Code/src/custom/components/request-detail/Form16WorkflowTab.tsx

126 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Form 16 Details Workflow tab.
* Shows the Form 16 process: Dealer submits → OCR extracts → 26AS match → Credit note.
* RE actions (cancel, resubmission needed, generate credit note) are in the Quick Actions sidebar.
*/
import { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { CheckCircle, Circle, XCircle, FileText, RefreshCw, Loader2, Receipt } from 'lucide-react';
import { getCreditNoteByRequestId, type Form16CreditNoteItem } from '@/services/form16Api';
interface Form16WorkflowTabProps {
request: any;
requestId: string;
isReUser: boolean;
onRefresh?: () => void;
}
const steps = [
{ key: 'submit', label: 'Dealer submits Form 16', icon: FileText },
{ key: 'ocr', label: 'OCR extracts', icon: FileText },
{ key: 'match', label: 'Matching with 26AS', icon: RefreshCw },
{ key: 'success', label: 'Successfully match', icon: CheckCircle },
{ key: 'credit', label: 'Credit note generated', icon: Receipt },
];
export function Form16WorkflowTab({ request, requestId }: Form16WorkflowTabProps) {
const [creditNote, setCreditNote] = useState<Form16CreditNoteItem | null>(null);
const [loading, setLoading] = useState(true);
const form16 = request?.form16Submission;
const hasSubmission = !!form16;
const hasCreditNote = !!creditNote && creditNote.status !== 'withdrawn';
const creditNoteWithdrawn = !!creditNote && creditNote.status === 'withdrawn';
const validationStatus = form16?.validationStatus ?? null;
const validationFailed = validationStatus === 'failed' || validationStatus === 'mismatch' || validationStatus === 'duplicate';
const validationSuccess = hasCreditNote || validationStatus === 'success' || validationStatus === 'manually_approved';
useEffect(() => {
if (!requestId) {
setLoading(false);
return;
}
let cancelled = false;
(async () => {
try {
const note = await getCreditNoteByRequestId(requestId);
if (!cancelled) setCreditNote(note);
} catch {
if (!cancelled) setCreditNote(null);
} finally {
if (!cancelled) setLoading(false);
}
})();
return () => { cancelled = true; };
}, [requestId]);
const stepStatus: Record<string, boolean> = {
submit: true,
ocr: hasSubmission,
match: validationSuccess,
success: validationSuccess,
credit: hasCreditNote || creditNoteWithdrawn,
};
const stepFailed: Record<string, boolean> = {
submit: false,
ocr: false,
match: validationFailed,
success: validationFailed,
credit: false,
};
return (
<div className="space-y-6" data-testid="form16-workflow-tab">
<Card className="border-emerald-200">
<CardHeader className="pb-2">
<CardTitle className="text-base flex items-center gap-2 text-emerald-800">
<RefreshCw className="w-4 h-4" />
Form 16 process
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{steps.map((step) => {
const done = stepStatus[step.key];
const failed = stepFailed[step.key];
return (
<div key={step.key} className="flex items-start gap-3">
<div className={`flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center ${failed ? 'bg-red-100 text-red-600' : done ? 'bg-emerald-100 text-emerald-700' : 'bg-gray-100 text-gray-400'}`}>
{failed ? <XCircle className="w-4 h-4" /> : done ? <CheckCircle className="w-4 h-4" /> : <Circle className="w-4 h-4" />}
</div>
<div className="flex-1 min-w-0">
<p className={`text-sm font-medium ${failed ? 'text-red-700' : done ? 'text-gray-900' : 'text-gray-500'}`}>{step.label}</p>
{step.key === 'credit' && hasCreditNote && creditNote && (
<p className="text-xs text-gray-500 mt-0.5">
Credit note: {creditNote.creditNoteNumber}
{creditNote.amount != null && ` · ${new Intl.NumberFormat('en-IN', { style: 'currency', currency: 'INR', maximumFractionDigits: 0 }).format(Number(creditNote.amount))}`}
{validationStatus === 'manually_approved' && (
<span className="ml-1 text-blue-600">(Manually approved Form 16)</span>
)}
</p>
)}
{step.key === 'credit' && creditNoteWithdrawn && (
<p className="text-xs text-amber-600 mt-0.5">Withdrawn</p>
)}
</div>
</div>
);
})}
</CardContent>
</Card>
{loading && (
<div className="flex items-center gap-2 text-sm text-gray-500">
<Loader2 className="w-4 h-4 animate-spin" />
Loading credit note
</div>
)}
{!hasCreditNote && !loading && hasSubmission && (
<p className="text-xs text-gray-500">No credit note has been generated for this submission yet. Use Quick Actions (sidebar) for RE actions.</p>
)}
</div>
);
}