teqo/src/components/campaign/MunicipalitySortableHead.tsx
Francisco Ignácio Fontoura Solla 96bf362421 B16: Filtros no header da lista de municípios
Popover de filtro por coluna no desktop (multi-seleção OR em município,
território, assessores e tendência; busca acento-insensível e "Limpar"),
mantendo os selects empilhados no mobile. Header sticky com a página como
scroller e empty state que substitui só as linhas de conteúdo, preservando
overview e filtros. Remove a coluna "Assessoria": a ordenação foi para
"Assessores" e o com/sem assessor virou opção do mesmo popover.
2026-07-25 03:13:28 -03:00

134 lines
4 KiB
TypeScript

'use client'
import { ChevronDownIcon, ChevronsUpDownIcon, ChevronUpIcon } from 'lucide-react'
import type { ReactNode } from 'react'
import { CampaignTransitionAnchor } from '@/components/campaign/CampaignListPending'
import { MunicipalityHeaderFilter } from '@/components/campaign/MunicipalityHeaderFilter'
import { MunicipalityHoverTooltip } from '@/components/campaign/MunicipalityHoverTooltip'
import { TableHead } from '@/components/ui/Table'
import { cn } from '@/lib/utils'
import {
buildMunicipalitySortHref,
defaultMunicipalityListSortDir,
municipalityListSortLabels,
resolveMunicipalityListSort,
type MunicipalityFilterOption,
type MunicipalityFilterParam,
type MunicipalityListSortKey,
type MunicipalityListState,
} from '@/utilities/municipalityUi'
type MunicipalitySortableHeadProps = {
state: MunicipalityListState
sortKey: MunicipalityListSortKey
children?: ReactNode
tooltip?: ReactNode
className?: string
align?: 'left' | 'center' | 'right'
filterParam?: MunicipalityFilterParam
filterOptions?: MunicipalityFilterOption[]
showPriorityFilter?: boolean
}
export const MunicipalitySortableHead = ({
state,
sortKey,
children,
tooltip,
className,
align = 'left',
filterParam,
filterOptions,
showPriorityFilter,
}: MunicipalitySortableHeadProps) => {
const href = buildMunicipalitySortHref(state, sortKey)
const { sort: activeSort, dir } = resolveMunicipalityListSort(state)
const active = activeSort === sortKey
const label = children ?? municipalityListSortLabels[sortKey]
const ariaSort = active ? (dir === 'asc' ? 'ascending' : 'descending') : 'none'
const nextDir = active
? dir === 'asc'
? 'desc'
: 'asc'
: defaultMunicipalityListSortDir(sortKey)
const nextDirLabel = nextDir === 'asc' ? 'crescente' : 'decrescente'
const sortControl = (
<CampaignTransitionAnchor
href={href}
replace
scroll={false}
className={cn(
'group inline-flex min-h-11 items-center gap-1 rounded-md text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
'hover:text-foreground',
active ? 'font-medium' : 'font-normal',
align === 'right' && !filterParam && 'w-full justify-end',
align === 'center' && !filterParam && 'w-full justify-center',
)}
aria-label={
active
? `Ordenar por ${municipalityListSortLabels[sortKey]}, inverter para ${nextDirLabel}`
: `Ordenar por ${municipalityListSortLabels[sortKey]} (${nextDirLabel})`
}
>
<span>{label}</span>
{active ? (
dir === 'asc' ? (
<ChevronUpIcon className="size-3.5 shrink-0" aria-hidden="true" />
) : (
<ChevronDownIcon className="size-3.5 shrink-0" aria-hidden="true" />
)
) : (
<ChevronsUpDownIcon
className="size-3.5 shrink-0 opacity-60 group-hover:opacity-100 group-focus-visible:opacity-100"
aria-hidden="true"
/>
)}
</CampaignTransitionAnchor>
)
const labeledSort = tooltip ? (
<MunicipalityHoverTooltip
content={tooltip}
align={align === 'right' ? 'end' : align === 'center' ? 'center' : 'start'}
>
{sortControl}
</MunicipalityHoverTooltip>
) : (
sortControl
)
return (
<TableHead
aria-sort={ariaSort}
className={cn(
'text-muted-foreground',
align === 'right' && 'text-right',
align === 'center' && 'text-center',
align === 'left' && 'text-left',
className,
)}
>
{filterParam ? (
<div
className={cn(
'flex items-center',
align === 'right' && 'justify-end',
align === 'center' && 'justify-center',
)}
>
{labeledSort}
<MunicipalityHeaderFilter
state={state}
filterParam={filterParam}
options={filterOptions}
showPriorityFilter={showPriorityFilter}
/>
</div>
) : (
labeledSort
)}
</TableHead>
)
}