118 lines
4.2 KiB
TypeScript
118 lines
4.2 KiB
TypeScript
/**
|
||
* 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 { Loader2, Receipt, X, RotateCcw } from 'lucide-react';
|
||
import {
|
||
getCreditNoteByRequestId,
|
||
cancelForm16Submission,
|
||
setForm16ResubmissionNeeded,
|
||
} 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' | null>(null);
|
||
|
||
const form16 = request?.form16Submission;
|
||
const hasSubmission = !!form16;
|
||
const hasCreditNote = !!creditNote && creditNote.status !== 'withdrawn';
|
||
|
||
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);
|
||
}
|
||
};
|
||
|
||
if (loading || !hasSubmission || hasCreditNote) return null;
|
||
|
||
return (
|
||
<Card className="border-blue-200 bg-blue-50/30" data-testid="form16-quick-actions-card">
|
||
<CardHeader className="pb-2">
|
||
<CardTitle className="text-sm flex items-center gap-2 text-blue-800">
|
||
<Receipt className="w-4 h-4" />
|
||
Form 16 actions
|
||
</CardTitle>
|
||
<CardDescription className="text-xs text-gray-600">
|
||
View the document in the Documents tab. Cancel submission or mark resubmission needed.
|
||
</CardDescription>
|
||
</CardHeader>
|
||
<CardContent className="space-y-2">
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
className="w-full justify-start border-red-300 text-red-700 hover:bg-red-50"
|
||
onClick={handleCancelSubmission}
|
||
disabled={!!actionLoading}
|
||
>
|
||
{actionLoading === 'cancel' ? <Loader2 className="w-3 h-3 animate-spin mr-1" /> : <X className="w-3 h-3 mr-1" />}
|
||
Cancel submission
|
||
</Button>
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
className="w-full justify-start border-amber-300 text-amber-700 hover:bg-amber-50"
|
||
onClick={handleResubmissionNeeded}
|
||
disabled={!!actionLoading}
|
||
>
|
||
{actionLoading === 'resubmit' ? <Loader2 className="w-3 h-3 animate-spin mr-1" /> : <RotateCcw className="w-3 h-3 mr-1" />}
|
||
Resubmission needed
|
||
</Button>
|
||
</CardContent>
|
||
</Card>
|
||
);
|
||
}
|