Re_Figma_Code/src/pages/RequestDetail/components/claim-cards/ProposalDetailsCard.tsx

162 lines
5.5 KiB
TypeScript

/**
* ProposalDetailsCard Component
* Displays proposal details submitted by dealer for Claim Management requests
*/
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
import { Receipt, Calendar } from 'lucide-react';
import { format } from 'date-fns';
// Minimal local types to avoid missing imports during runtime
interface ProposalCostItem {
description: string;
amount?: number | null;
}
interface ProposalDetails {
costBreakup: ProposalCostItem[];
estimatedBudgetTotal?: number | null;
timelineForClosure?: string | null;
dealerComments?: string | null;
submittedOn?: string | null;
}
interface ProposalDetailsCardProps {
proposalDetails: ProposalDetails;
className?: string;
}
export function ProposalDetailsCard({ proposalDetails, className }: ProposalDetailsCardProps) {
// Calculate estimated total from costBreakup if not provided
const calculateEstimatedTotal = () => {
if (proposalDetails.estimatedBudgetTotal !== undefined && proposalDetails.estimatedBudgetTotal !== null) {
return proposalDetails.estimatedBudgetTotal;
}
// Calculate sum from costBreakup items
if (proposalDetails.costBreakup && proposalDetails.costBreakup.length > 0) {
const total = proposalDetails.costBreakup.reduce((sum, item) => {
const amount = item.amount || 0;
return sum + (Number.isNaN(amount) ? 0 : amount);
}, 0);
return total;
}
return 0;
};
const estimatedTotal = calculateEstimatedTotal();
const formatCurrency = (amount?: number | null) => {
if (amount === undefined || amount === null || Number.isNaN(amount)) {
return '₹0.00';
}
return `${amount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
};
const formatDate = (dateString?: string | null) => {
if (!dateString) return '';
try {
return format(new Date(dateString), 'MMM d, yyyy, h:mm a');
} catch {
return dateString || '';
}
};
const formatTimelineDate = (dateString?: string | null) => {
if (!dateString) return '-';
try {
return format(new Date(dateString), 'MMM d, yyyy');
} catch {
return dateString || '-';
}
};
return (
<Card className={className}>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-base">
<Receipt className="w-5 h-5 text-green-600" />
Proposal Details
</CardTitle>
{proposalDetails.submittedOn && (
<CardDescription>
Submitted on {formatDate(proposalDetails.submittedOn)}
</CardDescription>
)}
</CardHeader>
<CardContent className="space-y-4">
{/* Cost Breakup */}
<div>
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide mb-3 block">
Cost Breakup
</label>
<div className="border rounded-lg overflow-hidden">
<table className="w-full">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-2 text-left text-xs font-semibold text-gray-700 uppercase tracking-wide">
Item Description
</th>
<th className="px-4 py-2 text-right text-xs font-semibold text-gray-700 uppercase tracking-wide">
Amount
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
{(proposalDetails.costBreakup || []).map((item, index) => (
<tr key={index} className="hover:bg-gray-50">
<td className="px-4 py-3 text-sm text-gray-900">
{item.description}
</td>
<td className="px-4 py-3 text-sm text-gray-900 text-right font-medium">
{formatCurrency(item.amount)}
</td>
</tr>
))}
<tr className="bg-green-50 font-semibold">
<td className="px-4 py-3 text-sm text-gray-900">
Estimated Budget (Total)
</td>
<td className="px-4 py-3 text-sm text-green-700 text-right">
{formatCurrency(estimatedTotal)}
</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Timeline for Closure */}
<div className="pt-2">
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
Timeline for Closure
</label>
<div className="mt-2 bg-blue-50 border border-blue-200 rounded-lg p-3">
<div className="flex items-center gap-2">
<Calendar className="w-4 h-4 text-blue-600" />
<span className="text-sm font-medium text-gray-900">
Expected completion by: {formatTimelineDate(proposalDetails.timelineForClosure)}
</span>
</div>
</div>
</div>
{/* Dealer Comments */}
{proposalDetails.dealerComments && (
<div className="pt-2">
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
Dealer Comments
</label>
<p className="text-sm text-gray-700 mt-2 bg-gray-50 p-3 rounded-lg whitespace-pre-line">
{proposalDetails.dealerComments}
</p>
</div>
)}
</CardContent>
</Card>
);
}