178 lines
6.4 KiB
TypeScript
178 lines
6.4 KiB
TypeScript
/**
|
|
* ActivityInformationCard Component
|
|
* Displays activity details for Claim Management requests
|
|
*/
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Calendar, MapPin, DollarSign, Receipt } from 'lucide-react';
|
|
import { ClaimActivityInfo } from '../../types/claimManagement.types';
|
|
import { format } from 'date-fns';
|
|
|
|
interface ActivityInformationCardProps {
|
|
activityInfo: ClaimActivityInfo;
|
|
className?: string;
|
|
}
|
|
|
|
export function ActivityInformationCard({ activityInfo, className }: ActivityInformationCardProps) {
|
|
// Defensive check: Ensure activityInfo exists
|
|
if (!activityInfo) {
|
|
console.warn('[ActivityInformationCard] activityInfo is missing');
|
|
return (
|
|
<Card className={className}>
|
|
<CardContent className="py-8 text-center text-gray-500">
|
|
<p>Activity information not available</p>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
const formatCurrency = (amount: string | number) => {
|
|
const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
|
|
if (isNaN(numAmount)) return 'N/A';
|
|
return `₹${numAmount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
};
|
|
|
|
const formatDate = (dateString?: string) => {
|
|
if (!dateString) return 'N/A';
|
|
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">
|
|
<Calendar className="w-5 h-5 text-blue-600" />
|
|
Activity Information
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
{/* Activity Name */}
|
|
<div>
|
|
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
|
|
Activity Name
|
|
</label>
|
|
<p className="text-sm text-gray-900 font-medium mt-1">
|
|
{activityInfo.activityName}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Activity Type */}
|
|
<div>
|
|
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
|
|
Activity Type
|
|
</label>
|
|
<p className="text-sm text-gray-900 font-medium mt-1">
|
|
{activityInfo.activityType}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Location */}
|
|
<div>
|
|
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
|
|
Location
|
|
</label>
|
|
<p className="text-sm text-gray-900 font-medium mt-1 flex items-center gap-2">
|
|
<MapPin className="w-4 h-4 text-gray-400" />
|
|
{activityInfo.location}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Requested Date */}
|
|
<div>
|
|
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
|
|
Requested Date
|
|
</label>
|
|
<p className="text-sm text-gray-900 font-medium mt-1">
|
|
{formatDate(activityInfo.requestedDate)}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Estimated Budget */}
|
|
<div>
|
|
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
|
|
Estimated Budget
|
|
</label>
|
|
<p className="text-sm text-gray-900 font-medium mt-1 flex items-center gap-2">
|
|
<DollarSign className="w-4 h-4 text-green-600" />
|
|
{activityInfo.estimatedBudget
|
|
? formatCurrency(activityInfo.estimatedBudget)
|
|
: 'TBD'}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Closed Expenses */}
|
|
{activityInfo.closedExpenses !== undefined && (
|
|
<div>
|
|
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
|
|
Closed Expenses
|
|
</label>
|
|
<p className="text-sm text-gray-900 font-medium mt-1 flex items-center gap-2">
|
|
<Receipt className="w-4 h-4 text-blue-600" />
|
|
{formatCurrency(activityInfo.closedExpenses)}
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Period */}
|
|
{activityInfo.period && (
|
|
<div className="col-span-2">
|
|
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
|
|
Period
|
|
</label>
|
|
<p className="text-sm text-gray-900 font-medium mt-1">
|
|
{formatDate(activityInfo.period.startDate)} - {formatDate(activityInfo.period.endDate)}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Closed Expenses Breakdown */}
|
|
{activityInfo.closedExpensesBreakdown && activityInfo.closedExpensesBreakdown.length > 0 && (
|
|
<div className="pt-4 border-t">
|
|
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide mb-3 block">
|
|
Closed Expenses Breakdown
|
|
</label>
|
|
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3 space-y-2">
|
|
{activityInfo.closedExpensesBreakdown.map((item, index) => (
|
|
<div key={index} className="flex justify-between items-center text-sm">
|
|
<span className="text-gray-700">{item.description}</span>
|
|
<span className="font-medium text-gray-900">
|
|
{formatCurrency(item.amount)}
|
|
</span>
|
|
</div>
|
|
))}
|
|
<div className="pt-2 border-t border-blue-300 flex justify-between items-center">
|
|
<span className="font-semibold text-gray-900">Total</span>
|
|
<span className="font-bold text-blue-600">
|
|
{formatCurrency(
|
|
activityInfo.closedExpensesBreakdown.reduce((sum, item) => sum + item.amount, 0)
|
|
)}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Description */}
|
|
{activityInfo.description && (
|
|
<div className="pt-4 border-t">
|
|
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">
|
|
Description
|
|
</label>
|
|
<p className="text-sm text-gray-700 mt-2 bg-gray-50 p-3 rounded-lg whitespace-pre-line">
|
|
{activityInfo.description}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
|