Re_Figma_Code/src/dealer-claim/components/request-detail/claim-cards/ActivityInformationCard.tsx

203 lines
7.5 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 '@/pages/RequestDetail/types/claimManagement.types';
import { format } from 'date-fns';
import { formatDateTime } from '@/utils/dateFormatter';
interface ActivityInformationCardProps {
activityInfo: ClaimActivityInfo;
className?: string;
// Plug-and-play: Pass timestamps from module's business logic
createdAt?: string | Date;
updatedAt?: string | Date;
}
export function ActivityInformationCard({
activityInfo,
className,
createdAt,
updatedAt
}: 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 - Show if value exists (including 0) */}
{activityInfo.closedExpenses !== undefined && activityInfo.closedExpenses !== null && (
<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: { description: string; amount: number }, index: number) => (
<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: number, item: { description: string; amount: number }) => 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>
)}
{/* Timestamps - Similar to Request Details Card */}
{(createdAt || updatedAt) && (
<div className="grid grid-cols-2 gap-4 pt-4 border-t border-gray-300">
{createdAt && (
<div>
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">Created</label>
<p className="text-sm text-gray-900 font-medium mt-1">{formatDateTime(createdAt)}</p>
</div>
)}
{updatedAt && (
<div>
<label className="text-xs font-medium text-gray-500 uppercase tracking-wide">Last Updated</label>
<p className="text-sm text-gray-900 font-medium mt-1">{formatDateTime(updatedAt)}</p>
</div>
)}
</div>
)}
</CardContent>
</Card>
);
}