User select dropdowns: group all staff by department (Claims first, then alphabetical)
This commit is contained in:
parent
ff6135da5c
commit
ceb82c9ef7
1 changed files with 46 additions and 35 deletions
|
|
@ -1,8 +1,7 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { SelectContent, SelectGroup, SelectItem, SelectLabel } from '@/components/ui/select'
|
import { SelectContent, SelectGroup, SelectItem, SelectLabel } from '@/components/ui/select'
|
||||||
import { ChevronDown } from 'lucide-react'
|
|
||||||
|
|
||||||
export interface SelectableUser {
|
export interface SelectableUser {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -17,49 +16,61 @@ interface UserSelectContentProps {
|
||||||
prefixItem?: React.ReactNode
|
prefixItem?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export function UserSelectContent({ users, excludeIds = [], prefixItem }: UserSelectContentProps) {
|
/** Pretty-print a department slug (e.g. "private-client" → "Private Client") */
|
||||||
const [showAll, setShowAll] = useState(false)
|
function formatDepartment(dept: string): string {
|
||||||
|
return dept
|
||||||
|
.split('-')
|
||||||
|
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
||||||
|
.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
const eligible = users.filter((u) => !excludeIds.includes(u.id))
|
/** Departments shown first in this order; everything else follows alphabetically */
|
||||||
const claims = eligible.filter((u) => u.department?.toLowerCase().includes('claims'))
|
const PRIORITY_DEPARTMENTS = ['claims']
|
||||||
const rest = eligible.filter((u) => !u.department?.toLowerCase().includes('claims'))
|
|
||||||
|
export function UserSelectContent({ users, excludeIds = [], prefixItem }: UserSelectContentProps) {
|
||||||
|
const grouped = useMemo(() => {
|
||||||
|
const eligible = users.filter((u) => !excludeIds.includes(u.id))
|
||||||
|
|
||||||
|
const map = new Map<string, SelectableUser[]>()
|
||||||
|
for (const u of eligible) {
|
||||||
|
const key = (u.department || 'other').toLowerCase()
|
||||||
|
if (!map.has(key)) map.set(key, [])
|
||||||
|
map.get(key)!.push(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort users within each group
|
||||||
|
for (const list of map.values()) {
|
||||||
|
list.sort((a, b) =>
|
||||||
|
(a.displayName || a.email).localeCompare(b.displayName || b.email)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort department keys: priority first, then alphabetical
|
||||||
|
const keys = [...map.keys()].sort((a, b) => {
|
||||||
|
const ai = PRIORITY_DEPARTMENTS.indexOf(a)
|
||||||
|
const bi = PRIORITY_DEPARTMENTS.indexOf(b)
|
||||||
|
if (ai !== -1 && bi !== -1) return ai - bi
|
||||||
|
if (ai !== -1) return -1
|
||||||
|
if (bi !== -1) return 1
|
||||||
|
return a.localeCompare(b)
|
||||||
|
})
|
||||||
|
|
||||||
|
return keys.map((key) => ({ key, label: formatDepartment(key), users: map.get(key)! }))
|
||||||
|
}, [users, excludeIds])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{prefixItem}
|
{prefixItem}
|
||||||
{claims.length > 0 && (
|
{grouped.map((group) => (
|
||||||
<SelectGroup>
|
<SelectGroup key={group.key}>
|
||||||
<SelectLabel>Claims</SelectLabel>
|
<SelectLabel>{group.label}</SelectLabel>
|
||||||
{claims.map((u) => (
|
{group.users.map((u) => (
|
||||||
<SelectItem key={u.id} value={u.id}>
|
<SelectItem key={u.id} value={u.id}>
|
||||||
{u.displayName || u.email}
|
{u.displayName || u.email}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
)}
|
))}
|
||||||
{rest.length > 0 && (
|
|
||||||
<SelectGroup>
|
|
||||||
<SelectLabel
|
|
||||||
className="flex items-center justify-between cursor-pointer select-none hover:text-foreground"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
setShowAll((v) => !v)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>All Staff</span>
|
|
||||||
<ChevronDown
|
|
||||||
className={`h-3.5 w-3.5 transition-transform ${showAll ? 'rotate-180' : ''}`}
|
|
||||||
/>
|
|
||||||
</SelectLabel>
|
|
||||||
{showAll &&
|
|
||||||
rest.map((u) => (
|
|
||||||
<SelectItem key={u.id} value={u.id}>
|
|
||||||
{u.displayName || u.email}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectGroup>
|
|
||||||
)}
|
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue