mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-12 22:13:05 +00:00
The "Municípios" column was dead text; it is now chips that navigate to the município, with a territory chip when a leadership covers a whole TI, and it is editable in place. What picks inline vs. Drawer is the `pointer:` media query, not viewport width: on a fine pointer the editor is always mounted (the "×" sits at the chip's corner, revealed on hover/focus) and on a coarse pointer a tap anywhere in the cell opens a Drawer with 44 px targets. `AdvisorMunicipalityCell` is promoted to `shared/MunicipalityPortfolioCell` and /campanha/assessores migrates onto it in the same change, so the second call site is born with the first. One batch action only; the single-id advisor twin is deleted with its int tests migrated. The anti-goal on always-mounted list inputs is amended for chip-based relations on fine pointers, not reopened. Also fixes a latent bug: `CampaignTableHead`'s `description` seam broke any RSC caller, because its two helpers lived in a 'use client' module.
91 lines
2.7 KiB
TypeScript
91 lines
2.7 KiB
TypeScript
'use client'
|
|
|
|
import type { ReactNode } from 'react'
|
|
|
|
import { MunicipalityHeaderFilter } from '@/components/campaign/municipality/MunicipalityHeaderFilter'
|
|
import { CampaignHoverTooltip } from '@/components/campaign/shared/CampaignHoverTooltip'
|
|
import { CampaignSortableHead } from '@/components/campaign/shared/CampaignSortableHead'
|
|
import {
|
|
campaignHoverExplanationClassName,
|
|
campaignHoverTooltipAlign,
|
|
} from '@/lib/campaignHoverTooltip'
|
|
import type {
|
|
MunicipalityFilterOption,
|
|
MunicipalityFilterParam,
|
|
} from '@/utilities/municipalityListFilters'
|
|
import {
|
|
buildMunicipalitySortHref,
|
|
defaultMunicipalityListSortDir,
|
|
municipalityListSortLabels,
|
|
resolveMunicipalityListSort,
|
|
type MunicipalityListSortKey,
|
|
type MunicipalityListState,
|
|
} from '@/utilities/municipalityListUrl'
|
|
|
|
type MunicipalitySortableHeadProps = {
|
|
state: MunicipalityListState
|
|
sortKey: MunicipalityListSortKey
|
|
children?: ReactNode
|
|
/** Hover/focus/tap explanation for the column (B22) — names the content, not the mechanism. */
|
|
description?: ReactNode
|
|
className?: string
|
|
align?: 'left' | 'center' | 'right'
|
|
filterParam?: MunicipalityFilterParam
|
|
/** Pairs, or bare catalog slugs labeled on the client (B16+ payload trim). */
|
|
filterOptions?: MunicipalityFilterOption[] | readonly string[]
|
|
showPriorityFilter?: boolean
|
|
}
|
|
|
|
export const MunicipalitySortableHead = ({
|
|
state,
|
|
sortKey,
|
|
children,
|
|
description,
|
|
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 nextDir = active
|
|
? dir === 'asc'
|
|
? 'desc'
|
|
: 'asc'
|
|
: defaultMunicipalityListSortDir(sortKey)
|
|
return (
|
|
<CampaignSortableHead
|
|
active={active}
|
|
align={align}
|
|
className={className}
|
|
dir={dir}
|
|
href={href}
|
|
nextDir={nextDir}
|
|
sortLabel={municipalityListSortLabels[sortKey]}
|
|
filter={
|
|
filterParam ? (
|
|
<MunicipalityHeaderFilter
|
|
state={state}
|
|
filterParam={filterParam}
|
|
options={filterOptions}
|
|
showPriorityFilter={showPriorityFilter}
|
|
/>
|
|
) : null
|
|
}
|
|
wrapSortControl={
|
|
description
|
|
? (control) => (
|
|
<CampaignHoverTooltip content={description} align={campaignHoverTooltipAlign(align)}>
|
|
{control}
|
|
</CampaignHoverTooltip>
|
|
)
|
|
: undefined
|
|
}
|
|
>
|
|
{description ? <span className={campaignHoverExplanationClassName}>{label}</span> : label}
|
|
</CampaignSortableHead>
|
|
)
|
|
}
|