feat: parent/child company badges in client header
- Parent companies show a violet badge with subsidiary count, clickable to open modal - Modal lists each subsidiary with policy count, task count, and claims advocate, click to navigate - Child companies show a blue badge with parent name, clickable to navigate to parent page - Both badges update reactively with state
This commit is contained in:
parent
170bb35921
commit
4774eb1932
2 changed files with 77 additions and 2 deletions
|
|
@ -40,6 +40,7 @@ export default async function ClientDetailPage({
|
|||
id: true,
|
||||
name: true,
|
||||
_count: { select: { tasks: true, policies: true } },
|
||||
claimsAdvocate: { select: { id: true, displayName: true, email: true } },
|
||||
},
|
||||
orderBy: { name: 'asc' },
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,6 +6,12 @@ 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 {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -14,7 +20,7 @@ import {
|
|||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { Building2, MapPin, Phone, Mail, FileText, CheckSquare, CalendarRange, Users, X, Plus, UserCheck, StickyNote, Pencil, Trash2, ChevronDown, ChevronUp, ArrowUp, ArrowDown, ArrowUpDown } from 'lucide-react'
|
||||
import { Building2, MapPin, Phone, Mail, FileText, CheckSquare, CalendarRange, Users, X, Plus, UserCheck, StickyNote, Pencil, Trash2, ChevronDown, ChevronUp, ArrowUp, ArrowDown, ArrowUpDown, GitBranch, ChevronRight } from 'lucide-react'
|
||||
import { Combobox } from '@/components/ui/combobox'
|
||||
import { formatDate, formatRenewalDate } from '@/lib/utils'
|
||||
import { PolicyGroupManager } from '@/components/clients/policy-group-manager'
|
||||
|
|
@ -53,6 +59,7 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic
|
|||
const [parentOptions, setParentOptions] = useState<{id:string;name:string}[]>([])
|
||||
const [parentLinking, setParentLinking] = useState(false)
|
||||
const [showArchivedTasks, setShowArchivedTasks] = useState(false)
|
||||
const [subsidiariesModalOpen, setSubsidiariesModalOpen] = useState(false)
|
||||
const [taskSort, setTaskSort] = useState<'date' | 'priority'>('date')
|
||||
const [taskSortDir, setTaskSortDir] = useState<'asc' | 'desc'>('asc')
|
||||
const [showCompleted, setShowCompleted] = useState(false)
|
||||
|
|
@ -290,6 +297,9 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic
|
|||
}
|
||||
}
|
||||
|
||||
const isParent = subsidiaries.length > 0
|
||||
const isChild = !!parentClient
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Header */}
|
||||
|
|
@ -299,7 +309,7 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic
|
|||
<Building2 className="h-8 w-8" />
|
||||
{client.name}
|
||||
</h1>
|
||||
<div className="flex gap-4 mt-3 text-sm text-muted-foreground">
|
||||
<div className="flex flex-wrap gap-4 mt-3 text-sm text-muted-foreground">
|
||||
{client.city && client.state && (
|
||||
<div className="flex items-center gap-1">
|
||||
<MapPin className="h-4 w-4" />
|
||||
|
|
@ -319,9 +329,73 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Parent / Child badges */}
|
||||
<div className="flex flex-wrap gap-2 mt-3">
|
||||
{isParent && (
|
||||
<button
|
||||
onClick={() => setSubsidiariesModalOpen(true)}
|
||||
className="inline-flex items-center gap-1.5 rounded-full border border-violet-500/40 bg-violet-500/10 px-3 py-1 text-xs font-medium text-violet-700 dark:text-violet-400 hover:bg-violet-500/20 transition-colors"
|
||||
>
|
||||
<GitBranch className="h-3.5 w-3.5" />
|
||||
Parent Company · {subsidiaries.length} {subsidiaries.length === 1 ? 'subsidiary' : 'subsidiaries'}
|
||||
</button>
|
||||
)}
|
||||
{isChild && (
|
||||
<Link
|
||||
href={`/clients/${parentClient!.id}`}
|
||||
className="inline-flex items-center gap-1.5 rounded-full border border-blue-500/40 bg-blue-500/10 px-3 py-1 text-xs font-medium text-blue-700 dark:text-blue-400 hover:bg-blue-500/20 transition-colors"
|
||||
>
|
||||
<ChevronRight className="h-3.5 w-3.5 rotate-180" />
|
||||
Child of {parentClient!.name}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Subsidiaries modal */}
|
||||
<Dialog open={subsidiariesModalOpen} onOpenChange={setSubsidiariesModalOpen}>
|
||||
<DialogContent className="sm:max-w-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<GitBranch className="h-5 w-5" />
|
||||
Subsidiaries of {client.name}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="space-y-2 max-h-[60vh] overflow-y-auto pr-1">
|
||||
{subsidiaries.map((sub: any) => (
|
||||
<Link
|
||||
key={sub.id}
|
||||
href={`/clients/${sub.id}`}
|
||||
onClick={() => setSubsidiariesModalOpen(false)}
|
||||
className="flex items-center justify-between rounded-lg border border-border p-3 hover:bg-muted/50 transition-colors group"
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-medium text-sm group-hover:text-primary transition-colors truncate">{sub.name}</p>
|
||||
{sub.claimsAdvocate && (
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
Advocate: {sub.claimsAdvocate.displayName || sub.claimsAdvocate.email}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-3 ml-4 shrink-0 text-xs text-muted-foreground">
|
||||
<span className="flex items-center gap-1">
|
||||
<FileText className="h-3.5 w-3.5" />
|
||||
{sub._count?.policies ?? 0}
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<CheckSquare className="h-3.5 w-3.5" />
|
||||
{sub._count?.tasks ?? 0}
|
||||
</span>
|
||||
<ChevronRight className="h-4 w-4 opacity-40 group-hover:opacity-100 transition-opacity" />
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Client Notes — collapsible */}
|
||||
<div className="rounded-lg border bg-card">
|
||||
<button
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue