seubert-claims/ondeck/src/components/policies/policy-detail.tsx
lorentz b036a93da2 Initial commit: OnDeck project
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 13:20:52 +00:00

289 lines
10 KiB
TypeScript

'use client'
import Link from 'next/link'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import {
ArrowLeft,
Building2,
Calendar,
DollarSign,
FileText,
Users,
CheckSquare,
Briefcase,
CreditCard,
Shield
} from 'lucide-react'
import { formatDate } from '@/lib/utils'
interface PolicyDetailProps {
policy: any
}
export function PolicyDetail({ policy }: PolicyDetailProps) {
const isExpired = new Date(policy.expirationDate) < new Date()
const daysUntilExpiration = Math.ceil(
(new Date(policy.expirationDate).getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24)
)
return (
<div className="space-y-6">
{/* Header */}
<div className="flex items-start justify-between">
<div className="space-y-1">
<div className="flex items-center gap-2">
<Link href={`/clients/${policy.client.id}`}>
<Button variant="ghost" size="sm">
<ArrowLeft className="h-4 w-4 mr-2" />
Back to {policy.client.name}
</Button>
</Link>
</div>
<h1 className="text-3xl font-bold">{policy.policyType || 'Type LOB'}</h1>
<p className="text-muted-foreground">
Policy #{policy.policyNumber || 'N/A'}
</p>
</div>
<div className="text-right">
<Badge
variant={isExpired ? 'destructive' : daysUntilExpiration <= 30 ? 'destructive' : daysUntilExpiration <= 90 ? 'secondary' : 'default'}
className="text-sm"
>
{isExpired ? 'Expired' : `Expires in ${daysUntilExpiration} days`}
</Badge>
<p className="text-sm text-muted-foreground mt-2">
<span suppressHydrationWarning>{formatDate(policy.expirationDate)}</span>
</p>
</div>
</div>
{/* Client Info Card */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Building2 className="h-5 w-5" />
Client Information
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
<div>
<p className="text-sm text-muted-foreground">Client Name</p>
<p className="font-medium">{policy.client.name}</p>
</div>
{policy.client.city && (
<div>
<p className="text-sm text-muted-foreground">Location</p>
<p className="font-medium">
{[policy.client.city, policy.client.state].filter(Boolean).join(', ')}
</p>
</div>
)}
{policy.client.designation && (
<div>
<p className="text-sm text-muted-foreground">Primary Designation</p>
<Badge variant="outline">{policy.client.designation.name}</Badge>
</div>
)}
</div>
</CardContent>
</Card>
{/* Policy Details Grid */}
<div className="grid gap-6 md:grid-cols-2">
{/* Coverage Information */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Shield className="h-5 w-5" />
Coverage Information
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div>
<p className="text-sm text-muted-foreground">Type LOB</p>
<p className="font-medium text-lg">{policy.policyType || 'N/A'}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<p className="text-sm text-muted-foreground">Effective Date</p>
<p className="font-medium">
<span suppressHydrationWarning>
{policy.effectiveDate ? formatDate(policy.effectiveDate) : 'N/A'}
</span>
</p>
</div>
<div>
<p className="text-sm text-muted-foreground">Expiration Date</p>
<p className="font-medium">
<span suppressHydrationWarning>
{formatDate(policy.expirationDate)}
</span>
</p>
</div>
</div>
{policy.status && (
<div>
<p className="text-sm text-muted-foreground">Status</p>
<Badge>{policy.status}</Badge>
</div>
)}
{policy.businessType && (
<div>
<p className="text-sm text-muted-foreground">Business Type</p>
<p className="font-medium">{policy.businessType}</p>
</div>
)}
</CardContent>
</Card>
{/* Carrier & Financial */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Briefcase className="h-5 w-5" />
Carrier & Financial
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{policy.writingCompanyName && (
<div>
<p className="text-sm text-muted-foreground">Writing Company</p>
<p className="font-medium">{policy.writingCompanyName}</p>
</div>
)}
{policy.carrierName && (
<div>
<p className="text-sm text-muted-foreground">Parent Company</p>
<p className="font-medium">{policy.carrierName}</p>
</div>
)}
{policy.billMethod && (
<div>
<p className="text-sm text-muted-foreground">Billing Method</p>
<p className="font-medium">{policy.billMethod}</p>
</div>
)}
{policy.premiumAmount && (
<div>
<p className="text-sm text-muted-foreground">Premium Amount</p>
<p className="font-medium text-lg">
${policy.premiumAmount.toLocaleString()}
</p>
</div>
)}
</CardContent>
</Card>
</div>
{/* Personnel Information */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Users className="h-5 w-5" />
Assigned Personnel
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 md:grid-cols-3 gap-6">
{policy.department && (
<div>
<p className="text-sm text-muted-foreground">Department</p>
<Badge variant="outline" className="mt-1">{policy.department}</Badge>
</div>
)}
{policy.executiveName && (
<div>
<p className="text-sm text-muted-foreground">Executive</p>
<p className="font-medium">{policy.executiveName}</p>
</div>
)}
{policy.csrName && (
<div>
<p className="text-sm text-muted-foreground">CSR</p>
<p className="font-medium">{policy.csrName}</p>
</div>
)}
</div>
{/* Additional Personnel */}
{(policy.additionalRep1 || policy.additionalRep2 || policy.additionalExec1 || policy.additionalExec2) && (
<div className="mt-6 pt-6 border-t">
<p className="text-sm text-muted-foreground mb-3">Additional Personnel</p>
<div className="flex flex-wrap gap-2">
{policy.additionalRep1 && (
<Badge variant="secondary">Rep: {policy.additionalRep1}</Badge>
)}
{policy.additionalRep2 && (
<Badge variant="secondary">Rep: {policy.additionalRep2}</Badge>
)}
{policy.additionalExec1 && (
<Badge variant="secondary">Exec: {policy.additionalExec1}</Badge>
)}
{policy.additionalExec2 && (
<Badge variant="secondary">Exec: {policy.additionalExec2}</Badge>
)}
</div>
</div>
)}
</CardContent>
</Card>
{/* Tasks Tab */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CheckSquare className="h-5 w-5" />
Renewal Tasks ({policy.tasks.length})
</CardTitle>
</CardHeader>
<CardContent>
{policy.tasks.length === 0 ? (
<p className="text-center text-muted-foreground py-8">
No tasks assigned to this policy
</p>
) : (
<div className="space-y-3">
{policy.tasks.map((task: any) => (
<div key={task.id} className="flex items-start justify-between p-4 border rounded-lg">
<div className="flex-1">
<h4 className="font-semibold">{task.title}</h4>
{task.description && (
<p className="text-sm text-muted-foreground mt-1">{task.description}</p>
)}
{task.assignments.length > 0 && (
<div className="flex gap-2 mt-2">
{task.assignments.map((assignment: any) => (
<Badge key={assignment.id} variant="outline" className="text-xs">
{assignment.user.displayName}
</Badge>
))}
</div>
)}
</div>
<div className="text-right ml-4">
<Badge variant={
task.status === 'COMPLETED' ? 'default' :
task.status === 'IN_PROGRESS' ? 'secondary' :
task.status === 'BLOCKED' ? 'destructive' : 'outline'
}>
{task.status}
</Badge>
{task.dueDate && (
<p className="text-xs text-muted-foreground mt-1">
Due: <span suppressHydrationWarning>{formatDate(task.dueDate)}</span>
</p>
)}
</div>
</div>
))}
</div>
)}
</CardContent>
</Card>
</div>
)
}