1508 lines
68 KiB
TypeScript
1508 lines
68 KiB
TypeScript
import { useState } from 'react';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/card';
|
|
import { Badge } from '../ui/badge';
|
|
import { Button } from '../ui/button';
|
|
import { Input } from '../ui/input';
|
|
import { Label } from '../ui/label';
|
|
import { Textarea } from '../ui/textarea';
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../ui/tabs';
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../ui/table';
|
|
import { Progress } from '../ui/progress';
|
|
import {
|
|
ArrowLeft,
|
|
DollarSign,
|
|
CheckCircle,
|
|
XCircle,
|
|
Upload,
|
|
FileText,
|
|
Calendar,
|
|
User,
|
|
MapPin,
|
|
AlertCircle,
|
|
Wallet,
|
|
Receipt,
|
|
TrendingUp,
|
|
TrendingDown,
|
|
Building,
|
|
CreditCard,
|
|
Hash,
|
|
Send,
|
|
Users,
|
|
Plus,
|
|
Edit2,
|
|
Trash2,
|
|
Save,
|
|
Calculator
|
|
} from 'lucide-react';
|
|
import { toast } from 'sonner';
|
|
import { departments } from '../../lib/mock-data';
|
|
|
|
interface FinanceFnFDetailsPageProps {
|
|
fnfId: string;
|
|
onBack: () => void;
|
|
}
|
|
|
|
// Mock data - in real app this would come from API
|
|
const getFnFData = (id: string) => {
|
|
return {
|
|
id: id,
|
|
caseNumber: 'FNF-2024-001',
|
|
dealerName: 'Rajesh Kumar',
|
|
dealerCode: 'DLR-001',
|
|
location: 'Mumbai, Maharashtra',
|
|
terminationType: 'Resignation',
|
|
submittedDate: '2025-09-15',
|
|
dueDate: '2025-10-20',
|
|
status: 'Pending Finance Review',
|
|
financialData: {
|
|
// Payables (Company owes dealer)
|
|
securityDeposit: 500000,
|
|
inventoryValue: 1200000,
|
|
equipmentValue: 300000,
|
|
|
|
// Receivables (Dealer owes company)
|
|
outstandingInvoices: 450000,
|
|
serviceDues: 75000,
|
|
partsDues: 125000,
|
|
advancesGiven: 200000,
|
|
penalties: 50000,
|
|
otherCharges: 25000,
|
|
|
|
// Deductions
|
|
warrantyPending: 100000,
|
|
},
|
|
bankDetails: {
|
|
accountName: 'Rajesh Kumar',
|
|
accountNumber: '1234567890',
|
|
ifscCode: 'HDFC0001234',
|
|
bankName: 'HDFC Bank',
|
|
branch: 'Mumbai Central'
|
|
},
|
|
documents: [
|
|
{ name: 'Resignation Letter.pdf', size: '245 KB', uploadedOn: '2025-09-15', type: 'Resignation' },
|
|
{ name: 'Asset Handover Receipt.pdf', size: '312 KB', uploadedOn: '2025-09-16', type: 'Asset' },
|
|
{ name: 'Inventory Report.xlsx', size: '856 KB', uploadedOn: '2025-09-17', type: 'Inventory' },
|
|
{ name: 'Bank Statement.pdf', size: '1.2 MB', uploadedOn: '2025-09-15', type: 'Financial' }
|
|
],
|
|
departmentResponses: departments.map((dept, index) => ({
|
|
id: `dept-${index + 1}`,
|
|
departmentName: dept,
|
|
status: index < 8 ? 'NOC Submitted' : index < 12 ? 'Dues Pending' : 'Pending',
|
|
remarks: index < 8 ? 'No outstanding dues, clearance provided' : index < 12 ? 'Outstanding amount to be recovered' : 'Awaiting department response',
|
|
amountType: index === 8 ? 'Recovery Amount' : index === 9 ? 'Payable Amount' : index === 10 ? 'Recovery Amount' : undefined,
|
|
amount: index === 8 ? 75000 : index === 9 ? 12000 : index === 10 ? 125000 : undefined,
|
|
submittedDate: index < 12 ? '2025-10-05' : undefined,
|
|
submittedBy: index < 12 ? `${dept} Head` : undefined
|
|
}))
|
|
};
|
|
};
|
|
|
|
const calculateSettlement = (financialData: any) => {
|
|
const payables = financialData.securityDeposit + financialData.inventoryValue + financialData.equipmentValue;
|
|
const receivables =
|
|
financialData.outstandingInvoices +
|
|
financialData.serviceDues +
|
|
financialData.partsDues +
|
|
financialData.advancesGiven +
|
|
financialData.penalties +
|
|
financialData.otherCharges;
|
|
const deductions = financialData.warrantyPending;
|
|
const netSettlement = payables - receivables - deductions;
|
|
|
|
return {
|
|
payables,
|
|
receivables,
|
|
deductions,
|
|
netSettlement,
|
|
settlementAmount: Math.abs(netSettlement),
|
|
settlementType: netSettlement > 0 ? 'Payable to Dealer' : 'Recovery from Dealer'
|
|
};
|
|
};
|
|
|
|
const getDepartmentStatusColor = (status: string) => {
|
|
switch (status) {
|
|
case 'NOC Submitted':
|
|
return 'bg-green-100 text-green-700 border-green-300';
|
|
case 'Dues Pending':
|
|
return 'bg-red-100 text-red-700 border-red-300';
|
|
case 'Completed':
|
|
return 'bg-green-100 text-green-700 border-green-300';
|
|
case 'Pending':
|
|
return 'bg-slate-100 text-slate-700 border-slate-300';
|
|
default:
|
|
return 'bg-slate-100 text-slate-700 border-slate-300';
|
|
}
|
|
};
|
|
|
|
interface FinancialLineItem {
|
|
id: string;
|
|
department: string;
|
|
description: string;
|
|
amount: number;
|
|
}
|
|
|
|
export function FinanceFnFDetailsPage({ fnfId, onBack }: FinanceFnFDetailsPageProps) {
|
|
const fnfCase = getFnFData(fnfId);
|
|
|
|
// Initialize editable line items from mock data
|
|
const [payableItems, setPayableItems] = useState<FinancialLineItem[]>([
|
|
{ id: '1', department: 'Security Deposit', description: 'Refundable security deposit', amount: fnfCase.financialData.securityDeposit },
|
|
{ id: '2', department: 'Inventory', description: 'Vehicle inventory value', amount: fnfCase.financialData.inventoryValue },
|
|
{ id: '3', department: 'Equipment', description: 'Equipment and fixtures value', amount: fnfCase.financialData.equipmentValue }
|
|
]);
|
|
|
|
const [receivableItems, setReceivableItems] = useState<FinancialLineItem[]>([
|
|
{ id: '1', department: 'Sales', description: 'Outstanding invoices', amount: fnfCase.financialData.outstandingInvoices },
|
|
{ id: '2', department: 'Service', description: 'Service dues', amount: fnfCase.financialData.serviceDues },
|
|
{ id: '3', department: 'Parts', description: 'Parts dues', amount: fnfCase.financialData.partsDues },
|
|
{ id: '4', department: 'Finance', description: 'Advances given to dealer', amount: fnfCase.financialData.advancesGiven },
|
|
{ id: '5', department: 'Compliance', description: 'Penalties and fines', amount: fnfCase.financialData.penalties },
|
|
{ id: '6', department: 'Other', description: 'Miscellaneous charges', amount: fnfCase.financialData.otherCharges }
|
|
]);
|
|
|
|
const [deductionItems, setDeductionItems] = useState<FinancialLineItem[]>([
|
|
{ id: '1', department: 'Warranty', description: 'Pending warranty claims', amount: fnfCase.financialData.warrantyPending }
|
|
]);
|
|
|
|
// Form states for adding new items
|
|
const [newPayable, setNewPayable] = useState({ department: '', description: '', amount: '' });
|
|
const [newReceivable, setNewReceivable] = useState({ department: '', description: '', amount: '' });
|
|
const [newDeduction, setNewDeduction] = useState({ department: '', description: '', amount: '' });
|
|
|
|
// Edit mode states
|
|
const [editingPayableId, setEditingPayableId] = useState<string | null>(null);
|
|
const [editingReceivableId, setEditingReceivableId] = useState<string | null>(null);
|
|
const [editingDeductionId, setEditingDeductionId] = useState<string | null>(null);
|
|
|
|
// Calculate dynamic settlement
|
|
const calculateDynamicSettlement = () => {
|
|
const payables = payableItems.reduce((sum, item) => sum + item.amount, 0);
|
|
const receivables = receivableItems.reduce((sum, item) => sum + item.amount, 0);
|
|
const deductions = deductionItems.reduce((sum, item) => sum + item.amount, 0);
|
|
const netSettlement = payables - receivables - deductions;
|
|
|
|
return {
|
|
payables,
|
|
receivables,
|
|
deductions,
|
|
netSettlement,
|
|
settlementAmount: Math.abs(netSettlement),
|
|
settlementType: netSettlement > 0 ? 'Payable to Dealer' : netSettlement < 0 ? 'Recovery from Dealer' : 'No Settlement Required'
|
|
};
|
|
};
|
|
|
|
const settlement = calculateDynamicSettlement();
|
|
|
|
const [settlementDetails, setSettlementDetails] = useState({
|
|
verificationTransactionId: '',
|
|
settlementAmount: settlement.settlementAmount.toString(),
|
|
settlementDate: new Date().toISOString().split('T')[0],
|
|
paymentMode: '',
|
|
bankReference: '',
|
|
verificationRemarks: '',
|
|
adjustments: '0'
|
|
});
|
|
|
|
const [uploadedDocuments, setUploadedDocuments] = useState<any[]>([]);
|
|
|
|
// Handlers for Payables
|
|
const handleAddPayable = () => {
|
|
if (!newPayable.department || !newPayable.description || !newPayable.amount) {
|
|
toast.error('Please fill in all fields');
|
|
return;
|
|
}
|
|
const item: FinancialLineItem = {
|
|
id: Date.now().toString(),
|
|
department: newPayable.department,
|
|
description: newPayable.description,
|
|
amount: parseFloat(newPayable.amount)
|
|
};
|
|
setPayableItems([...payableItems, item]);
|
|
setNewPayable({ department: '', description: '', amount: '' });
|
|
toast.success('Payable item added');
|
|
};
|
|
|
|
const handleUpdatePayable = (id: string, field: keyof FinancialLineItem, value: string | number) => {
|
|
setPayableItems(payableItems.map(item =>
|
|
item.id === id ? { ...item, [field]: field === 'amount' ? parseFloat(value.toString()) : value } : item
|
|
));
|
|
};
|
|
|
|
const handleDeletePayable = (id: string) => {
|
|
setPayableItems(payableItems.filter(item => item.id !== id));
|
|
toast.info('Payable item removed');
|
|
};
|
|
|
|
// Handlers for Receivables
|
|
const handleAddReceivable = () => {
|
|
if (!newReceivable.department || !newReceivable.description || !newReceivable.amount) {
|
|
toast.error('Please fill in all fields');
|
|
return;
|
|
}
|
|
const item: FinancialLineItem = {
|
|
id: Date.now().toString(),
|
|
department: newReceivable.department,
|
|
description: newReceivable.description,
|
|
amount: parseFloat(newReceivable.amount)
|
|
};
|
|
setReceivableItems([...receivableItems, item]);
|
|
setNewReceivable({ department: '', description: '', amount: '' });
|
|
toast.success('Receivable item added');
|
|
};
|
|
|
|
const handleUpdateReceivable = (id: string, field: keyof FinancialLineItem, value: string | number) => {
|
|
setReceivableItems(receivableItems.map(item =>
|
|
item.id === id ? { ...item, [field]: field === 'amount' ? parseFloat(value.toString()) : value } : item
|
|
));
|
|
};
|
|
|
|
const handleDeleteReceivable = (id: string) => {
|
|
setReceivableItems(receivableItems.filter(item => item.id !== id));
|
|
toast.info('Receivable item removed');
|
|
};
|
|
|
|
// Handlers for Deductions
|
|
const handleAddDeduction = () => {
|
|
if (!newDeduction.department || !newDeduction.description || !newDeduction.amount) {
|
|
toast.error('Please fill in all fields');
|
|
return;
|
|
}
|
|
const item: FinancialLineItem = {
|
|
id: Date.now().toString(),
|
|
department: newDeduction.department,
|
|
description: newDeduction.description,
|
|
amount: parseFloat(newDeduction.amount)
|
|
};
|
|
setDeductionItems([...deductionItems, item]);
|
|
setNewDeduction({ department: '', description: '', amount: '' });
|
|
toast.success('Deduction item added');
|
|
};
|
|
|
|
const handleUpdateDeduction = (id: string, field: keyof FinancialLineItem, value: string | number) => {
|
|
setDeductionItems(deductionItems.map(item =>
|
|
item.id === id ? { ...item, [field]: field === 'amount' ? parseFloat(value.toString()) : value } : item
|
|
));
|
|
};
|
|
|
|
const handleDeleteDeduction = (id: string) => {
|
|
setDeductionItems(deductionItems.filter(item => item.id !== id));
|
|
toast.info('Deduction item removed');
|
|
};
|
|
|
|
const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
const files = event.target.files;
|
|
if (files && files.length > 0) {
|
|
const newDocs = Array.from(files).map(file => ({
|
|
name: file.name,
|
|
size: `${(file.size / 1024).toFixed(0)} KB`,
|
|
uploadedOn: new Date().toISOString().split('T')[0],
|
|
type: 'Settlement Verification'
|
|
}));
|
|
setUploadedDocuments([...uploadedDocuments, ...newDocs]);
|
|
toast.success(`${files.length} document(s) uploaded successfully`);
|
|
}
|
|
};
|
|
|
|
const handleApproveSettlement = () => {
|
|
if (!settlementDetails.verificationTransactionId || !settlementDetails.settlementDate || !settlementDetails.paymentMode) {
|
|
toast.error('Please fill in all required settlement details');
|
|
return;
|
|
}
|
|
|
|
const adjustedAmount = settlement.settlementAmount + parseFloat(settlementDetails.adjustments || '0');
|
|
if (adjustedAmount.toString() !== settlementDetails.settlementAmount) {
|
|
toast.warning('Settlement amount has been adjusted');
|
|
}
|
|
|
|
toast.success(`F&F Settlement approved for ${fnfCase.dealerName}`);
|
|
setTimeout(() => onBack(), 1500);
|
|
};
|
|
|
|
const handleRejectSettlement = () => {
|
|
if (!settlementDetails.verificationRemarks) {
|
|
toast.error('Please provide remarks for rejection');
|
|
return;
|
|
}
|
|
|
|
toast.error(`F&F Settlement rejected for ${fnfCase.dealerName}`);
|
|
setTimeout(() => onBack(), 1500);
|
|
};
|
|
|
|
const handleRequestClarification = () => {
|
|
if (!settlementDetails.verificationRemarks) {
|
|
toast.error('Please provide details for clarification request');
|
|
return;
|
|
}
|
|
|
|
toast.info(`Clarification request sent for ${fnfCase.dealerName}`);
|
|
setTimeout(() => onBack(), 1500);
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Header */}
|
|
<div className="flex items-center gap-4">
|
|
<Button variant="outline" size="icon" onClick={onBack}>
|
|
<ArrowLeft className="w-4 h-4" />
|
|
</Button>
|
|
<div>
|
|
<h1 className="text-3xl mb-1">F&F Settlement Review</h1>
|
|
<p className="text-slate-600">Full & Final Settlement for {fnfCase.dealerName}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Status Banner */}
|
|
<Card className="border-amber-200 bg-amber-50">
|
|
<CardContent className="pt-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-12 h-12 rounded-full bg-amber-100 flex items-center justify-center">
|
|
<DollarSign className="w-6 h-6 text-amber-600" />
|
|
</div>
|
|
<div>
|
|
<p className="text-slate-900">Settlement Pending Finance Approval</p>
|
|
<p className="text-sm text-slate-600">Case: {fnfCase.caseNumber} • Due: {fnfCase.dueDate}</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<Badge className="bg-amber-600">
|
|
{fnfCase.status}
|
|
</Badge>
|
|
<Badge variant={fnfCase.terminationType === 'Resignation' ? 'default' : 'secondary'}>
|
|
{fnfCase.terminationType}
|
|
</Badge>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Settlement Summary Card */}
|
|
<Card className={`${
|
|
settlement.settlementType === 'Payable to Dealer'
|
|
? 'border-red-300 bg-red-50'
|
|
: settlement.settlementType === 'Recovery from Dealer'
|
|
? 'border-green-300 bg-green-50'
|
|
: 'border-slate-300 bg-slate-50'
|
|
}`}>
|
|
<CardContent className="pt-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-4">
|
|
{settlement.settlementType === 'Payable to Dealer' ? (
|
|
<TrendingDown className="w-12 h-12 text-red-600" />
|
|
) : settlement.settlementType === 'Recovery from Dealer' ? (
|
|
<TrendingUp className="w-12 h-12 text-green-600" />
|
|
) : (
|
|
<CheckCircle className="w-12 h-12 text-slate-600" />
|
|
)}
|
|
<div>
|
|
<p className={`text-sm ${
|
|
settlement.settlementType === 'Payable to Dealer'
|
|
? 'text-red-700'
|
|
: settlement.settlementType === 'Recovery from Dealer'
|
|
? 'text-green-700'
|
|
: 'text-slate-700'
|
|
}`}>
|
|
{settlement.settlementType}
|
|
</p>
|
|
<p className="text-3xl text-slate-900">
|
|
{settlement.settlementType === 'No Settlement Required'
|
|
? '₹0'
|
|
: `₹${settlement.settlementAmount.toLocaleString('en-IN')}`}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="text-right">
|
|
<p className="text-sm text-slate-600">Net Settlement Amount</p>
|
|
<p className="text-xs text-slate-500 mt-1">
|
|
{settlement.settlementType === 'Payable to Dealer'
|
|
? 'Company will pay to dealer'
|
|
: settlement.settlementType === 'Recovery from Dealer'
|
|
? 'Dealer must pay to company'
|
|
: 'No payment required'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
{/* Left Column - Case Details & Financial Info */}
|
|
<div className="lg:col-span-2 space-y-6">
|
|
<Tabs defaultValue="overview" className="w-full">
|
|
<TabsList className="grid w-full grid-cols-5">
|
|
<TabsTrigger value="overview">Overview</TabsTrigger>
|
|
<TabsTrigger value="financial">Financial</TabsTrigger>
|
|
<TabsTrigger value="departments">Departments</TabsTrigger>
|
|
<TabsTrigger value="documents">Documents</TabsTrigger>
|
|
<TabsTrigger value="bank">Bank Details</TabsTrigger>
|
|
</TabsList>
|
|
|
|
<TabsContent value="overview" className="space-y-4">
|
|
{/* Case Information */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<User className="w-5 h-5" />
|
|
Case Information
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<Label className="text-slate-500">Case Number</Label>
|
|
<p className="text-slate-900">{fnfCase.caseNumber}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Dealer Code</Label>
|
|
<p className="text-slate-900">{fnfCase.dealerCode}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Dealer Name</Label>
|
|
<p className="text-slate-900">{fnfCase.dealerName}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Location</Label>
|
|
<p className="text-slate-900">{fnfCase.location}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Termination Type</Label>
|
|
<Badge variant={fnfCase.terminationType === 'Resignation' ? 'default' : 'secondary'}>
|
|
{fnfCase.terminationType}
|
|
</Badge>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Status</Label>
|
|
<Badge className="bg-amber-600">
|
|
{fnfCase.status}
|
|
</Badge>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Submitted Date</Label>
|
|
<p className="text-slate-900">{fnfCase.submittedDate}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Due Date</Label>
|
|
<p className="text-slate-900">{fnfCase.dueDate}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Request Age</Label>
|
|
<p className="text-slate-900">
|
|
{(() => {
|
|
const submitted = new Date(fnfCase.submittedDate);
|
|
const today = new Date();
|
|
const diffTime = Math.abs(today.getTime() - submitted.getTime());
|
|
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
return `${diffDays} day${diffDays !== 1 ? 's' : ''}`;
|
|
})()}
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Sales Code</Label>
|
|
<p className="text-slate-900">SAL-{fnfCase.dealerCode}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Service Code</Label>
|
|
<p className="text-slate-900">SRV-{fnfCase.dealerCode}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Gear Code</Label>
|
|
<p className="text-slate-900">GER-{fnfCase.dealerCode}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">GMA Code</Label>
|
|
<p className="text-slate-900">GMA-{fnfCase.dealerCode}</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Settlement Calculation Overview */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<DollarSign className="w-5 h-5" />
|
|
Settlement Calculation Summary
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="space-y-3">
|
|
<div className="flex justify-between items-center p-3 bg-green-50 rounded-lg">
|
|
<span className="text-slate-900">Total Payables (to Dealer)</span>
|
|
<span className="text-green-700 text-lg">+ ₹{settlement.payables.toLocaleString('en-IN')}</span>
|
|
</div>
|
|
<div className="flex justify-between items-center p-3 bg-red-50 rounded-lg">
|
|
<span className="text-slate-900">Total Receivables (from Dealer)</span>
|
|
<span className="text-red-700 text-lg">- ₹{settlement.receivables.toLocaleString('en-IN')}</span>
|
|
</div>
|
|
<div className="flex justify-between items-center p-3 bg-amber-50 rounded-lg">
|
|
<span className="text-slate-900">Total Deductions</span>
|
|
<span className="text-amber-700 text-lg">- ₹{settlement.deductions.toLocaleString('en-IN')}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="h-px bg-slate-300"></div>
|
|
|
|
<div className={`p-4 rounded-lg border-2 ${
|
|
settlement.settlementType === 'Payable to Dealer'
|
|
? 'bg-red-100 border-red-300'
|
|
: settlement.settlementType === 'Recovery from Dealer'
|
|
? 'bg-green-100 border-green-300'
|
|
: 'bg-slate-100 border-slate-300'
|
|
}`}>
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<span className="text-slate-900">Net Settlement</span>
|
|
<p className={`text-sm ${
|
|
settlement.settlementType === 'Payable to Dealer'
|
|
? 'text-red-700'
|
|
: settlement.settlementType === 'Recovery from Dealer'
|
|
? 'text-green-700'
|
|
: 'text-slate-700'
|
|
}`}>
|
|
{settlement.settlementType}
|
|
</p>
|
|
</div>
|
|
<span className="text-2xl text-slate-900">
|
|
{settlement.settlementType === 'No Settlement Required'
|
|
? '₹0'
|
|
: `₹${settlement.settlementAmount.toLocaleString('en-IN')}`}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-start gap-3 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
|
<AlertCircle className="w-5 h-5 text-blue-600 mt-0.5" />
|
|
<div>
|
|
<p className="text-sm text-slate-900 mb-1">Calculation Formula</p>
|
|
<p className="text-sm text-slate-600">
|
|
Net Settlement = Payables - Receivables - Deductions<br/>
|
|
<span className="text-xs">All amounts are editable in the Financial tab</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="financial" className="space-y-4">
|
|
{/* Payables - Editable */}
|
|
<Card className="border-green-200 bg-green-50">
|
|
<CardHeader>
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<CardTitle className="text-base flex items-center gap-2">
|
|
<Wallet className="w-5 h-5 text-green-600" />
|
|
Payables to Dealer (Editable)
|
|
</CardTitle>
|
|
<CardDescription>Add or modify amounts company owes to dealer</CardDescription>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
{/* Existing Payables */}
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Department</TableHead>
|
|
<TableHead>Description</TableHead>
|
|
<TableHead className="text-right">Amount (₹)</TableHead>
|
|
<TableHead className="w-[100px]">Actions</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{payableItems.map((item) => (
|
|
<TableRow key={item.id}>
|
|
<TableCell>
|
|
{editingPayableId === item.id ? (
|
|
<Input
|
|
value={item.department}
|
|
onChange={(e) => handleUpdatePayable(item.id, 'department', e.target.value)}
|
|
className="h-8"
|
|
/>
|
|
) : (
|
|
<span className="text-slate-900">{item.department}</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
{editingPayableId === item.id ? (
|
|
<Input
|
|
value={item.description}
|
|
onChange={(e) => handleUpdatePayable(item.id, 'description', e.target.value)}
|
|
className="h-8"
|
|
/>
|
|
) : (
|
|
<span className="text-slate-600">{item.description}</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell className="text-right">
|
|
{editingPayableId === item.id ? (
|
|
<Input
|
|
type="number"
|
|
value={item.amount}
|
|
onChange={(e) => handleUpdatePayable(item.id, 'amount', e.target.value)}
|
|
className="h-8 text-right"
|
|
/>
|
|
) : (
|
|
<span className="text-slate-900">₹{item.amount.toLocaleString('en-IN')}</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex gap-1">
|
|
{editingPayableId === item.id ? (
|
|
<Button
|
|
size="icon"
|
|
variant="ghost"
|
|
className="h-8 w-8"
|
|
onClick={() => {
|
|
setEditingPayableId(null);
|
|
toast.success('Changes saved');
|
|
}}
|
|
>
|
|
<Save className="w-4 h-4" />
|
|
</Button>
|
|
) : (
|
|
<Button
|
|
size="icon"
|
|
variant="ghost"
|
|
className="h-8 w-8"
|
|
onClick={() => setEditingPayableId(item.id)}
|
|
>
|
|
<Edit2 className="w-4 h-4" />
|
|
</Button>
|
|
)}
|
|
<Button
|
|
size="icon"
|
|
variant="ghost"
|
|
className="h-8 w-8 text-red-600 hover:text-red-700"
|
|
onClick={() => handleDeletePayable(item.id)}
|
|
>
|
|
<Trash2 className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
|
|
{/* Add New Payable */}
|
|
<div className="border-t border-green-300 pt-4 space-y-3">
|
|
<p className="text-sm text-slate-700">Add New Payable Item:</p>
|
|
<div className="grid grid-cols-12 gap-2">
|
|
<Input
|
|
placeholder="Department"
|
|
value={newPayable.department}
|
|
onChange={(e) => setNewPayable({ ...newPayable, department: e.target.value })}
|
|
className="col-span-3"
|
|
/>
|
|
<Input
|
|
placeholder="Description"
|
|
value={newPayable.description}
|
|
onChange={(e) => setNewPayable({ ...newPayable, description: e.target.value })}
|
|
className="col-span-5"
|
|
/>
|
|
<Input
|
|
type="number"
|
|
placeholder="Amount"
|
|
value={newPayable.amount}
|
|
onChange={(e) => setNewPayable({ ...newPayable, amount: e.target.value })}
|
|
className="col-span-3"
|
|
/>
|
|
<Button onClick={handleAddPayable} className="col-span-1 bg-green-600 hover:bg-green-700">
|
|
<Plus className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Total */}
|
|
<div className="pt-3 border-t-2 border-green-400">
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-900">Total Payables</span>
|
|
<span className="text-green-700 text-xl">
|
|
₹{settlement.payables.toLocaleString('en-IN')}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Receivables - Editable */}
|
|
<Card className="border-red-200 bg-red-50">
|
|
<CardHeader>
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<CardTitle className="text-base flex items-center gap-2">
|
|
<Receipt className="w-5 h-5 text-red-600" />
|
|
Receivables from Dealer (Editable)
|
|
</CardTitle>
|
|
<CardDescription>Add or modify amounts dealer owes to company</CardDescription>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
{/* Existing Receivables */}
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Department</TableHead>
|
|
<TableHead>Description</TableHead>
|
|
<TableHead className="text-right">Amount (₹)</TableHead>
|
|
<TableHead className="w-[100px]">Actions</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{receivableItems.map((item) => (
|
|
<TableRow key={item.id}>
|
|
<TableCell>
|
|
{editingReceivableId === item.id ? (
|
|
<Input
|
|
value={item.department}
|
|
onChange={(e) => handleUpdateReceivable(item.id, 'department', e.target.value)}
|
|
className="h-8"
|
|
/>
|
|
) : (
|
|
<span className="text-slate-900">{item.department}</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
{editingReceivableId === item.id ? (
|
|
<Input
|
|
value={item.description}
|
|
onChange={(e) => handleUpdateReceivable(item.id, 'description', e.target.value)}
|
|
className="h-8"
|
|
/>
|
|
) : (
|
|
<span className="text-slate-600">{item.description}</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell className="text-right">
|
|
{editingReceivableId === item.id ? (
|
|
<Input
|
|
type="number"
|
|
value={item.amount}
|
|
onChange={(e) => handleUpdateReceivable(item.id, 'amount', e.target.value)}
|
|
className="h-8 text-right"
|
|
/>
|
|
) : (
|
|
<span className="text-slate-900">₹{item.amount.toLocaleString('en-IN')}</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex gap-1">
|
|
{editingReceivableId === item.id ? (
|
|
<Button
|
|
size="icon"
|
|
variant="ghost"
|
|
className="h-8 w-8"
|
|
onClick={() => {
|
|
setEditingReceivableId(null);
|
|
toast.success('Changes saved');
|
|
}}
|
|
>
|
|
<Save className="w-4 h-4" />
|
|
</Button>
|
|
) : (
|
|
<Button
|
|
size="icon"
|
|
variant="ghost"
|
|
className="h-8 w-8"
|
|
onClick={() => setEditingReceivableId(item.id)}
|
|
>
|
|
<Edit2 className="w-4 h-4" />
|
|
</Button>
|
|
)}
|
|
<Button
|
|
size="icon"
|
|
variant="ghost"
|
|
className="h-8 w-8 text-red-600 hover:text-red-700"
|
|
onClick={() => handleDeleteReceivable(item.id)}
|
|
>
|
|
<Trash2 className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
|
|
{/* Add New Receivable */}
|
|
<div className="border-t border-red-300 pt-4 space-y-3">
|
|
<p className="text-sm text-slate-700">Add New Receivable Item:</p>
|
|
<div className="grid grid-cols-12 gap-2">
|
|
<Input
|
|
placeholder="Department"
|
|
value={newReceivable.department}
|
|
onChange={(e) => setNewReceivable({ ...newReceivable, department: e.target.value })}
|
|
className="col-span-3"
|
|
/>
|
|
<Input
|
|
placeholder="Description"
|
|
value={newReceivable.description}
|
|
onChange={(e) => setNewReceivable({ ...newReceivable, description: e.target.value })}
|
|
className="col-span-5"
|
|
/>
|
|
<Input
|
|
type="number"
|
|
placeholder="Amount"
|
|
value={newReceivable.amount}
|
|
onChange={(e) => setNewReceivable({ ...newReceivable, amount: e.target.value })}
|
|
className="col-span-3"
|
|
/>
|
|
<Button onClick={handleAddReceivable} className="col-span-1 bg-red-600 hover:bg-red-700">
|
|
<Plus className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Total */}
|
|
<div className="pt-3 border-t-2 border-red-400">
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-900">Total Receivables</span>
|
|
<span className="text-red-700 text-xl">
|
|
₹{settlement.receivables.toLocaleString('en-IN')}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Deductions - Editable */}
|
|
<Card className="border-amber-200 bg-amber-50">
|
|
<CardHeader>
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<CardTitle className="text-base flex items-center gap-2">
|
|
<AlertCircle className="w-5 h-5 text-amber-600" />
|
|
Deductions (Editable)
|
|
</CardTitle>
|
|
<CardDescription>Add or modify pending claims and deductions</CardDescription>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
{/* Existing Deductions */}
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Department</TableHead>
|
|
<TableHead>Description</TableHead>
|
|
<TableHead className="text-right">Amount (₹)</TableHead>
|
|
<TableHead className="w-[100px]">Actions</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{deductionItems.map((item) => (
|
|
<TableRow key={item.id}>
|
|
<TableCell>
|
|
{editingDeductionId === item.id ? (
|
|
<Input
|
|
value={item.department}
|
|
onChange={(e) => handleUpdateDeduction(item.id, 'department', e.target.value)}
|
|
className="h-8"
|
|
/>
|
|
) : (
|
|
<span className="text-slate-900">{item.department}</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
{editingDeductionId === item.id ? (
|
|
<Input
|
|
value={item.description}
|
|
onChange={(e) => handleUpdateDeduction(item.id, 'description', e.target.value)}
|
|
className="h-8"
|
|
/>
|
|
) : (
|
|
<span className="text-slate-600">{item.description}</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell className="text-right">
|
|
{editingDeductionId === item.id ? (
|
|
<Input
|
|
type="number"
|
|
value={item.amount}
|
|
onChange={(e) => handleUpdateDeduction(item.id, 'amount', e.target.value)}
|
|
className="h-8 text-right"
|
|
/>
|
|
) : (
|
|
<span className="text-slate-900">₹{item.amount.toLocaleString('en-IN')}</span>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex gap-1">
|
|
{editingDeductionId === item.id ? (
|
|
<Button
|
|
size="icon"
|
|
variant="ghost"
|
|
className="h-8 w-8"
|
|
onClick={() => {
|
|
setEditingDeductionId(null);
|
|
toast.success('Changes saved');
|
|
}}
|
|
>
|
|
<Save className="w-4 h-4" />
|
|
</Button>
|
|
) : (
|
|
<Button
|
|
size="icon"
|
|
variant="ghost"
|
|
className="h-8 w-8"
|
|
onClick={() => setEditingDeductionId(item.id)}
|
|
>
|
|
<Edit2 className="w-4 h-4" />
|
|
</Button>
|
|
)}
|
|
<Button
|
|
size="icon"
|
|
variant="ghost"
|
|
className="h-8 w-8 text-red-600 hover:text-red-700"
|
|
onClick={() => handleDeleteDeduction(item.id)}
|
|
>
|
|
<Trash2 className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
|
|
{/* Add New Deduction */}
|
|
<div className="border-t border-amber-300 pt-4 space-y-3">
|
|
<p className="text-sm text-slate-700">Add New Deduction Item:</p>
|
|
<div className="grid grid-cols-12 gap-2">
|
|
<Input
|
|
placeholder="Department"
|
|
value={newDeduction.department}
|
|
onChange={(e) => setNewDeduction({ ...newDeduction, department: e.target.value })}
|
|
className="col-span-3"
|
|
/>
|
|
<Input
|
|
placeholder="Description"
|
|
value={newDeduction.description}
|
|
onChange={(e) => setNewDeduction({ ...newDeduction, description: e.target.value })}
|
|
className="col-span-5"
|
|
/>
|
|
<Input
|
|
type="number"
|
|
placeholder="Amount"
|
|
value={newDeduction.amount}
|
|
onChange={(e) => setNewDeduction({ ...newDeduction, amount: e.target.value })}
|
|
className="col-span-3"
|
|
/>
|
|
<Button onClick={handleAddDeduction} className="col-span-1 bg-amber-600 hover:bg-amber-700">
|
|
<Plus className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Total */}
|
|
<div className="pt-3 border-t-2 border-amber-400">
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-900">Total Deductions</span>
|
|
<span className="text-amber-700 text-xl">
|
|
₹{settlement.deductions.toLocaleString('en-IN')}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Final Settlement Summary */}
|
|
<Card className="border-2 border-blue-300 bg-blue-50">
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Calculator className="w-5 h-5 text-blue-600" />
|
|
Final Settlement Summary
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="space-y-3">
|
|
<div className="flex justify-between items-center p-3 bg-white rounded-lg">
|
|
<span className="text-slate-900">Total Payables (to Dealer)</span>
|
|
<span className="text-green-700 text-lg">+ ₹{settlement.payables.toLocaleString('en-IN')}</span>
|
|
</div>
|
|
<div className="flex justify-between items-center p-3 bg-white rounded-lg">
|
|
<span className="text-slate-900">Total Receivables (from Dealer)</span>
|
|
<span className="text-red-700 text-lg">- ₹{settlement.receivables.toLocaleString('en-IN')}</span>
|
|
</div>
|
|
<div className="flex justify-between items-center p-3 bg-white rounded-lg">
|
|
<span className="text-slate-900">Total Deductions</span>
|
|
<span className="text-amber-700 text-lg">- ₹{settlement.deductions.toLocaleString('en-IN')}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="h-px bg-blue-300"></div>
|
|
|
|
<div className={`p-4 rounded-lg border-2 ${
|
|
settlement.settlementType === 'Payable to Dealer'
|
|
? 'bg-red-100 border-red-400'
|
|
: settlement.settlementType === 'Recovery from Dealer'
|
|
? 'bg-green-100 border-green-400'
|
|
: 'bg-slate-100 border-slate-400'
|
|
}`}>
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-sm text-slate-600 mb-1">Net Settlement</p>
|
|
<p className={`text-lg ${
|
|
settlement.settlementType === 'Payable to Dealer'
|
|
? 'text-red-700'
|
|
: settlement.settlementType === 'Recovery from Dealer'
|
|
? 'text-green-700'
|
|
: 'text-slate-700'
|
|
}`}>
|
|
{settlement.settlementType}
|
|
</p>
|
|
</div>
|
|
<span className="text-3xl text-slate-900">
|
|
{settlement.settlementType === 'No Settlement Required'
|
|
? '₹0'
|
|
: `₹${settlement.settlementAmount.toLocaleString('en-IN')}`}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-start gap-3 p-4 bg-white border border-blue-200 rounded-lg">
|
|
<AlertCircle className="w-5 h-5 text-blue-600 mt-0.5" />
|
|
<div>
|
|
<p className="text-sm text-slate-900 mb-1">Calculation Formula</p>
|
|
<p className="text-sm text-slate-600">
|
|
Net Settlement = Payables - Receivables - Deductions<br/>
|
|
{settlement.netSettlement > 0 && 'Positive value means company pays to dealer'}
|
|
{settlement.netSettlement < 0 && 'Negative value means dealer pays to company'}
|
|
{settlement.netSettlement === 0 && 'Zero means no payment required from either party'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="departments" className="space-y-4">
|
|
{/* Progress Summary */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Users className="w-5 h-5" />
|
|
Department Response Progress
|
|
</CardTitle>
|
|
<CardDescription>
|
|
{fnfCase.departmentResponses.filter((d: any) => d.status !== 'Pending').length} of {fnfCase.departmentResponses.length} departments have responded
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<Progress
|
|
value={(fnfCase.departmentResponses.filter((d: any) => d.status !== 'Pending').length / fnfCase.departmentResponses.length) * 100}
|
|
className="h-3"
|
|
/>
|
|
|
|
<div className="grid grid-cols-3 gap-4">
|
|
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
|
<p className="text-sm text-green-700 mb-1">NOC Submitted</p>
|
|
<p className="text-2xl text-green-600">
|
|
{fnfCase.departmentResponses.filter((d: any) => d.status === 'NOC Submitted').length}
|
|
</p>
|
|
</div>
|
|
<div className="p-4 bg-red-50 rounded-lg border border-red-200">
|
|
<p className="text-sm text-red-700 mb-1">Dues Pending</p>
|
|
<p className="text-2xl text-red-600">
|
|
{fnfCase.departmentResponses.filter((d: any) => d.status === 'Dues Pending').length}
|
|
</p>
|
|
</div>
|
|
<div className="p-4 bg-slate-50 rounded-lg border border-slate-200">
|
|
<p className="text-sm text-slate-700 mb-1">Awaiting Response</p>
|
|
<p className="text-2xl text-slate-600">
|
|
{fnfCase.departmentResponses.filter((d: any) => d.status === 'Pending').length}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Department Responses Table */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>All Department Responses</CardTitle>
|
|
<CardDescription>
|
|
Status of NOC and dues clearance from all 16 departments
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Department</TableHead>
|
|
<TableHead>Status</TableHead>
|
|
<TableHead>Amount Type</TableHead>
|
|
<TableHead>Amount</TableHead>
|
|
<TableHead>Submitted Date</TableHead>
|
|
<TableHead>Remarks</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{fnfCase.departmentResponses.map((dept: any) => (
|
|
<TableRow key={dept.id}>
|
|
<TableCell>{dept.departmentName}</TableCell>
|
|
<TableCell>
|
|
<Badge className={getDepartmentStatusColor(dept.status)}>
|
|
{dept.status}
|
|
</Badge>
|
|
</TableCell>
|
|
<TableCell>
|
|
{dept.amountType ? (
|
|
<Badge variant={dept.amountType === 'Recovery Amount' ? 'destructive' : 'default'}>
|
|
{dept.amountType}
|
|
</Badge>
|
|
) : (
|
|
'-'
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
{dept.amount ? (
|
|
<span className={dept.amountType === 'Recovery Amount' ? 'text-red-600' : 'text-green-600'}>
|
|
₹{dept.amount.toLocaleString('en-IN')}
|
|
</span>
|
|
) : (
|
|
'-'
|
|
)}
|
|
</TableCell>
|
|
<TableCell>{dept.submittedDate || '-'}</TableCell>
|
|
<TableCell className="max-w-xs truncate">{dept.remarks || '-'}</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Important Notes */}
|
|
<Card className="bg-blue-50 border-blue-200">
|
|
<CardContent className="pt-6">
|
|
<div className="flex items-start gap-3">
|
|
<AlertCircle className="w-5 h-5 text-blue-600 mt-0.5" />
|
|
<div>
|
|
<p className="text-sm text-slate-900 mb-1">Department Response Guidelines</p>
|
|
<ul className="text-sm text-slate-700 space-y-1">
|
|
<li>• <strong>NOC Submitted:</strong> Department has no outstanding dues and provided clearance</li>
|
|
<li>• <strong>Dues Pending:</strong> Department has identified amounts to be recovered or paid</li>
|
|
<li>• <strong>Pending:</strong> Department has not yet responded to the F&F request</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="documents" className="space-y-4">
|
|
{/* Submitted Documents */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<FileText className="w-5 h-5" />
|
|
Submitted Documents
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-2">
|
|
{fnfCase.documents.map((doc, index) => (
|
|
<div key={index} className="flex items-center justify-between p-3 bg-slate-50 rounded-lg border border-slate-200">
|
|
<div className="flex items-center gap-3">
|
|
<FileText className="w-5 h-5 text-slate-400" />
|
|
<div>
|
|
<p className="text-slate-900">{doc.name}</p>
|
|
<p className="text-sm text-slate-500">{doc.size} • {doc.type} • Uploaded on {doc.uploadedOn}</p>
|
|
</div>
|
|
</div>
|
|
<Button variant="outline" size="sm">
|
|
Download
|
|
</Button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Upload Additional Documents */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Upload className="w-5 h-5" />
|
|
Upload Settlement Verification Documents
|
|
</CardTitle>
|
|
<CardDescription>
|
|
Upload bank receipts, settlement proofs, or any additional documents
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="border-2 border-dashed border-slate-300 rounded-lg p-8 text-center hover:border-amber-400 hover:bg-amber-50 transition-colors">
|
|
<Upload className="w-8 h-8 text-slate-400 mx-auto mb-2" />
|
|
<p className="text-slate-600 mb-2">Click to upload or drag and drop</p>
|
|
<p className="text-sm text-slate-500">PDF, DOC, DOCX, PNG, JPG, XLSX (max 10MB)</p>
|
|
<input
|
|
type="file"
|
|
multiple
|
|
className="hidden"
|
|
id="file-upload"
|
|
onChange={handleFileUpload}
|
|
accept=".pdf,.doc,.docx,.png,.jpg,.jpeg,.xlsx,.xls"
|
|
/>
|
|
<label htmlFor="file-upload">
|
|
<Button variant="outline" className="mt-4" asChild>
|
|
<span>Choose Files</span>
|
|
</Button>
|
|
</label>
|
|
</div>
|
|
|
|
{uploadedDocuments.length > 0 && (
|
|
<div className="space-y-2">
|
|
<Label>Uploaded Documents</Label>
|
|
{uploadedDocuments.map((doc, index) => (
|
|
<div key={index} className="flex items-center justify-between p-3 bg-green-50 rounded-lg border border-green-200">
|
|
<div className="flex items-center gap-3">
|
|
<CheckCircle className="w-5 h-5 text-green-600" />
|
|
<div>
|
|
<p className="text-slate-900">{doc.name}</p>
|
|
<p className="text-sm text-slate-500">{doc.size} • {doc.type}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="bank" className="space-y-4">
|
|
{/* Bank Account Details */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Building className="w-5 h-5" />
|
|
Dealer Bank Account Details
|
|
</CardTitle>
|
|
<CardDescription>
|
|
Bank account for settlement transfer (if payable to dealer)
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<Label className="text-slate-500">Account Holder Name</Label>
|
|
<p className="text-slate-900">{fnfCase.bankDetails.accountName}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Account Number</Label>
|
|
<p className="text-slate-900">{fnfCase.bankDetails.accountNumber}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">IFSC Code</Label>
|
|
<p className="text-slate-900">{fnfCase.bankDetails.ifscCode}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Bank Name</Label>
|
|
<p className="text-slate-900">{fnfCase.bankDetails.bankName}</p>
|
|
</div>
|
|
<div>
|
|
<Label className="text-slate-500">Branch</Label>
|
|
<p className="text-slate-900">{fnfCase.bankDetails.branch}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
|
<div className="flex items-start gap-3">
|
|
<AlertCircle className="w-5 h-5 text-blue-600 mt-0.5" />
|
|
<div>
|
|
<p className="text-sm text-slate-900 mb-1">Bank Verification Required</p>
|
|
<p className="text-sm text-slate-600">
|
|
Please verify bank account details before processing settlement payment
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
|
|
{/* Right Column - Settlement Verification Form */}
|
|
<div className="space-y-6">
|
|
<Card className="sticky top-6">
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<CreditCard className="w-5 h-5" />
|
|
Settlement Verification
|
|
</CardTitle>
|
|
<CardDescription>
|
|
Enter settlement transaction details
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div>
|
|
<Label htmlFor="paymentMode">
|
|
Payment Mode <span className="text-red-500">*</span>
|
|
</Label>
|
|
<Input
|
|
id="paymentMode"
|
|
placeholder="e.g., NEFT, RTGS, Cheque"
|
|
value={settlementDetails.paymentMode}
|
|
onChange={(e) => setSettlementDetails({ ...settlementDetails, paymentMode: e.target.value })}
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<Label htmlFor="verificationTxnId">
|
|
Transaction ID / Reference <span className="text-red-500">*</span>
|
|
</Label>
|
|
<Input
|
|
id="verificationTxnId"
|
|
placeholder="Enter transaction reference"
|
|
value={settlementDetails.verificationTransactionId}
|
|
onChange={(e) => setSettlementDetails({ ...settlementDetails, verificationTransactionId: e.target.value })}
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<Label htmlFor="bankReference">
|
|
Bank Reference Number
|
|
</Label>
|
|
<Input
|
|
id="bankReference"
|
|
placeholder="Enter bank reference"
|
|
value={settlementDetails.bankReference}
|
|
onChange={(e) => setSettlementDetails({ ...settlementDetails, bankReference: e.target.value })}
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<Label htmlFor="settlementAmount">
|
|
Settlement Amount (₹) <span className="text-red-500">*</span>
|
|
</Label>
|
|
<Input
|
|
id="settlementAmount"
|
|
type="number"
|
|
placeholder="Enter settlement amount"
|
|
value={settlementDetails.settlementAmount}
|
|
onChange={(e) => setSettlementDetails({ ...settlementDetails, settlementAmount: e.target.value })}
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<Label htmlFor="adjustments">
|
|
Adjustments (₹)
|
|
</Label>
|
|
<Input
|
|
id="adjustments"
|
|
type="number"
|
|
placeholder="Enter any adjustments"
|
|
value={settlementDetails.adjustments}
|
|
onChange={(e) => {
|
|
const adjustments = e.target.value;
|
|
const adjustedAmount = settlement.settlementAmount + parseFloat(adjustments || '0');
|
|
setSettlementDetails({
|
|
...settlementDetails,
|
|
adjustments,
|
|
settlementAmount: adjustedAmount.toString()
|
|
});
|
|
}}
|
|
/>
|
|
{parseFloat(settlementDetails.adjustments) !== 0 && (
|
|
<p className="text-sm text-amber-600 mt-1 flex items-center gap-1">
|
|
<AlertCircle className="w-3 h-3" />
|
|
Adjusted amount: ₹{settlementDetails.settlementAmount}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<Label htmlFor="settlementDate">
|
|
Settlement Date <span className="text-red-500">*</span>
|
|
</Label>
|
|
<Input
|
|
id="settlementDate"
|
|
type="date"
|
|
value={settlementDetails.settlementDate}
|
|
onChange={(e) => setSettlementDetails({ ...settlementDetails, settlementDate: e.target.value })}
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<Label htmlFor="verificationRemarks">Verification Remarks</Label>
|
|
<Textarea
|
|
id="verificationRemarks"
|
|
placeholder="Enter any remarks or notes..."
|
|
rows={4}
|
|
value={settlementDetails.verificationRemarks}
|
|
onChange={(e) => setSettlementDetails({ ...settlementDetails, verificationRemarks: e.target.value })}
|
|
/>
|
|
</div>
|
|
|
|
<div className="pt-4 space-y-3 border-t">
|
|
<Button
|
|
className="w-full bg-green-600 hover:bg-green-700"
|
|
onClick={handleApproveSettlement}
|
|
>
|
|
<CheckCircle className="w-4 h-4 mr-2" />
|
|
Approve Settlement
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
className="w-full border-blue-300 text-blue-600 hover:bg-blue-50"
|
|
onClick={handleRequestClarification}
|
|
>
|
|
<Send className="w-4 h-4 mr-2" />
|
|
Request Clarification
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
className="w-full border-red-300 text-red-600 hover:bg-red-50"
|
|
onClick={handleRejectSettlement}
|
|
>
|
|
<XCircle className="w-4 h-4 mr-2" />
|
|
Reject Settlement
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Quick Info Card */}
|
|
<Card className="bg-blue-50 border-blue-200">
|
|
<CardHeader>
|
|
<CardTitle className="text-base">Settlement Checklist</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<ul className="space-y-2 text-sm text-slate-700">
|
|
<li className="flex items-start gap-2">
|
|
<CheckCircle className="w-4 h-4 text-blue-600 mt-0.5" />
|
|
<span>Verify all financial calculations</span>
|
|
</li>
|
|
<li className="flex items-start gap-2">
|
|
<CheckCircle className="w-4 h-4 text-blue-600 mt-0.5" />
|
|
<span>Confirm bank account details</span>
|
|
</li>
|
|
<li className="flex items-start gap-2">
|
|
<CheckCircle className="w-4 h-4 text-blue-600 mt-0.5" />
|
|
<span>Review all submitted documents</span>
|
|
</li>
|
|
<li className="flex items-start gap-2">
|
|
<CheckCircle className="w-4 h-4 text-blue-600 mt-0.5" />
|
|
<span>Upload settlement proof documents</span>
|
|
</li>
|
|
<li className="flex items-start gap-2">
|
|
<CheckCircle className="w-4 h-4 text-blue-600 mt-0.5" />
|
|
<span>Enter transaction details accurately</span>
|
|
</li>
|
|
</ul>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|