Re_Figma_Code/src/pages/RequestDetail/components/tabs/ClaimManagementWorkflowTab.tsx

312 lines
11 KiB
TypeScript

/**
* ClaimManagementWorkflowTab Component
* Displays the 8-step workflow process specific to Claim Management requests
*/
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
TrendingUp,
CircleCheckBig,
Clock,
Mail,
Download,
Receipt,
Activity,
AlertCircle,
} from 'lucide-react';
import { format } from 'date-fns';
interface WorkflowStep {
stepNumber: number;
stepName: string;
stepDescription: string;
assignedTo: string;
assignedToType: 'dealer' | 'requestor' | 'department_lead' | 'finance' | 'system';
status: 'pending' | 'in_progress' | 'approved' | 'rejected' | 'skipped';
tatHours: number;
elapsedHours?: number;
remarks?: string;
approvedAt?: string;
approvedBy?: string;
ioDetails?: {
ioNumber: string;
ioRemarks: string;
organisedBy: string;
organisedAt: string;
};
dmsDetails?: {
dmsNumber: string;
dmsRemarks: string;
pushedBy: string;
pushedAt: string;
};
hasEmailNotification?: boolean;
hasDownload?: boolean;
downloadUrl?: string;
}
interface ClaimManagementWorkflowTabProps {
steps: WorkflowStep[];
currentStep: number;
totalSteps?: number;
onViewEmailTemplate?: (stepNumber: number) => void;
onDownloadDocument?: (stepNumber: number, url: string) => void;
className?: string;
}
export function ClaimManagementWorkflowTab({
steps,
currentStep,
totalSteps = 8,
onViewEmailTemplate,
onDownloadDocument,
className = '',
}: ClaimManagementWorkflowTabProps) {
const formatDate = (dateString?: string) => {
if (!dateString) return 'N/A';
try {
return format(new Date(dateString), 'MMM d, yyyy, h:mm a');
} catch {
return dateString;
}
};
const getStepBorderColor = (status: string) => {
switch (status) {
case 'approved':
return 'border-green-500 bg-green-50';
case 'in_progress':
return 'border-blue-500 bg-blue-50';
case 'rejected':
return 'border-red-500 bg-red-50';
case 'pending':
return 'border-gray-300 bg-white';
case 'skipped':
return 'border-gray-400 bg-gray-50';
default:
return 'border-gray-300 bg-white';
}
};
const getStepIconBg = (status: string) => {
switch (status) {
case 'approved':
return 'bg-green-100';
case 'in_progress':
return 'bg-blue-100';
case 'rejected':
return 'bg-red-100';
case 'pending':
return 'bg-gray-100';
case 'skipped':
return 'bg-gray-200';
default:
return 'bg-gray-100';
}
};
const getStepIcon = (status: string) => {
switch (status) {
case 'approved':
return <CircleCheckBig className="w-5 h-5 text-green-600" />;
case 'in_progress':
return <Clock className="w-5 h-5 text-blue-600" />;
case 'rejected':
return <AlertCircle className="w-5 h-5 text-red-600" />;
case 'pending':
return <Clock className="w-5 h-5 text-gray-400" />;
default:
return <Clock className="w-5 h-5 text-gray-400" />;
}
};
const getStatusBadgeColor = (status: string) => {
switch (status) {
case 'approved':
return 'bg-green-100 text-green-800 border-green-200';
case 'in_progress':
return 'bg-blue-100 text-blue-800 border-blue-200';
case 'rejected':
return 'bg-red-100 text-red-800 border-red-200';
case 'pending':
return 'bg-gray-100 text-gray-600 border-gray-200';
case 'skipped':
return 'bg-gray-200 text-gray-700 border-gray-300';
default:
return 'bg-gray-100 text-gray-600 border-gray-200';
}
};
return (
<Card className={className}>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="leading-none flex items-center gap-2">
<TrendingUp className="w-5 h-5 text-purple-600" />
Claim Management Workflow
</CardTitle>
<CardDescription className="mt-2">
8-Step approval process for dealer claim management
</CardDescription>
</div>
<Badge variant="outline" className="font-medium">
Step {currentStep} of {totalSteps}
</Badge>
</div>
</CardHeader>
<CardContent>
<div className="space-y-4">
{steps.map((step, index) => (
<div
key={step.stepNumber}
className={`relative p-5 rounded-lg border-2 transition-all ${getStepBorderColor(step.status)}`}
>
{/* Step Content */}
<div className="flex items-start gap-4">
{/* Icon */}
<div className={`p-3 rounded-xl ${getStepIconBg(step.status)}`}>
{getStepIcon(step.status)}
</div>
{/* Step Details */}
<div className="flex-1 min-w-0">
{/* Header Row */}
<div className="flex items-start justify-between gap-4 mb-2">
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<h4 className="font-semibold text-gray-900">
Step {step.stepNumber}: {step.stepName}
</h4>
<Badge className={getStatusBadgeColor(step.status)}>
{step.status}
</Badge>
{/* Action Buttons */}
{step.hasEmailNotification && onViewEmailTemplate && (
<Button
variant="ghost"
size="sm"
className="h-6 w-6 p-0 hover:bg-blue-100"
onClick={() => onViewEmailTemplate(step.stepNumber)}
title="View email template"
>
<Mail className="w-3.5 h-3.5 text-blue-600" />
</Button>
)}
{step.hasDownload && onDownloadDocument && step.downloadUrl && (
<Button
variant="ghost"
size="sm"
className="h-6 w-6 p-0 hover:bg-green-100"
onClick={() => onDownloadDocument(step.stepNumber, step.downloadUrl!)}
title="Download E-Invoice"
>
<Download className="w-3.5 h-3.5 text-green-600" />
</Button>
)}
</div>
<p className="text-sm text-gray-600">{step.assignedTo}</p>
<p className="text-sm text-gray-500 mt-2 italic">
{step.stepDescription}
</p>
</div>
{/* TAT Info */}
<div className="text-right">
<p className="text-xs text-gray-500">TAT: {step.tatHours}h</p>
{step.elapsedHours !== undefined && (
<p className="text-xs text-gray-600 font-medium">
Elapsed: {step.elapsedHours}h
</p>
)}
</div>
</div>
{/* Remarks */}
{step.remarks && (
<div className="mt-3 p-3 bg-white rounded-lg border border-gray-200">
<p className="text-sm text-gray-700">{step.remarks}</p>
</div>
)}
{/* IO Details */}
{step.ioDetails && (
<div className="mt-3 p-3 bg-blue-50 rounded-lg border border-blue-200">
<div className="flex items-center gap-2 mb-2">
<Receipt className="w-4 h-4 text-blue-600" />
<p className="text-xs font-semibold text-blue-900 uppercase tracking-wide">
IO Organisation Details
</p>
</div>
<div className="space-y-1.5">
<div className="flex items-center justify-between">
<span className="text-xs text-gray-600">IO Number:</span>
<span className="text-sm font-semibold text-gray-900">
{step.ioDetails.ioNumber}
</span>
</div>
<div className="pt-1.5 border-t border-blue-100">
<p className="text-xs text-gray-600 mb-1">IO Remark:</p>
<p className="text-sm text-gray-900">{step.ioDetails.ioRemarks}</p>
</div>
<div className="pt-1.5 border-t border-blue-100 text-xs text-gray-500">
Organised by {step.ioDetails.organisedBy} on{' '}
{formatDate(step.ioDetails.organisedAt)}
</div>
</div>
</div>
)}
{/* DMS Details */}
{step.dmsDetails && (
<div className="mt-3 p-3 bg-purple-50 rounded-lg border border-purple-200">
<div className="flex items-center gap-2 mb-2">
<Activity className="w-4 h-4 text-purple-600" />
<p className="text-xs font-semibold text-purple-900 uppercase tracking-wide">
DMS Processing Details
</p>
</div>
<div className="space-y-1.5">
<div className="flex items-center justify-between">
<span className="text-xs text-gray-600">DMS Number:</span>
<span className="text-sm font-semibold text-gray-900">
{step.dmsDetails.dmsNumber}
</span>
</div>
<div className="pt-1.5 border-t border-purple-100">
<p className="text-xs text-gray-600 mb-1">DMS Remarks:</p>
<p className="text-sm text-gray-900">{step.dmsDetails.dmsRemarks}</p>
</div>
<div className="pt-1.5 border-t border-purple-100 text-xs text-gray-500">
Pushed by {step.dmsDetails.pushedBy} on{' '}
{formatDate(step.dmsDetails.pushedAt)}
</div>
</div>
</div>
)}
{/* Approval Timestamp */}
{step.approvedAt && (
<p className="text-xs text-gray-500 mt-2">
{step.status === 'approved' ? 'Approved' : 'Updated'} on{' '}
{formatDate(step.approvedAt)}
</p>
)}
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
);
}