teqo/src/components/campaign/MunicipalityAdvisorAvatarStack.tsx
Francisco Ignácio Fontoura Solla e2724c10da Remodel the campaign vertical from Praça to Município
Rename the operational unit "Praça"/"Núcleo" to "Município" (code identifier
`municipality`) and land the 2026-07-23 course changes:

- New `candidate` role with unrestricted visibility (`isCampaignStaff` now
  includes it) alongside coordinator/advisor; leader is locked down to the
  supporter contact tool only.
- Demandas become staff-only; dobradinhas modeled via a `stateDeputy` entity.
- Camaçari consolidated to a single município (ZE 170/171 aggregated);
  Salvador keeps its 19 zone municípios.
- Map moves to the staff dashboard; `/campanha/municipios` is list/overview.
- Vote pledges keep the declared vs estimated (scenario) asymmetry; leaders
  never see estimates.

Destructive migration for the campaign vertical (drops nucleus/plaza-era
tables, wipes campaign rows, seeds 435 municípios). Public-site data untouched.

Includes the post-delivery /simplify cleanups: shared reloadStaffActor /
reloadCoordinatorActor helpers, req.context cache for getFreshCampaignUser,
parallelized dashboard loads, candidate dashboard-copy fix, and dead
leader-dashboard / roleKind code removal.
2026-07-23 21:36:20 -03:00

37 lines
1 KiB
TypeScript

import { Avatar, AvatarFallback } from '@/components/ui/Avatar'
export const campaignUserInitials = (name: string): string =>
name
.split(/\s+/)
.slice(0, 2)
.map((part) => part[0])
.join('')
.toUpperCase()
export type MunicipalityAdvisorAvatarEntry = {
id: number
name: string
}
export const MunicipalityAdvisorAvatarStack = ({
advisors,
maxVisible = 3,
}: {
advisors: MunicipalityAdvisorAvatarEntry[]
maxVisible?: number
}) => {
if (!advisors.length) return <span className="text-muted-foreground">Sem assessor</span>
return (
<div className="flex items-center gap-2">
<div className="flex -space-x-2">
{advisors.slice(0, maxVisible).map((advisor) => (
<Avatar key={advisor.id} className="size-8 border-2 border-background">
<AvatarFallback>{campaignUserInitials(advisor.name)}</AvatarFallback>
</Avatar>
))}
</div>
<span className="sr-only">{advisors.map((advisor) => advisor.name).join(', ')}</span>
</div>
)
}