436 seeded Praças (municipality-based; per-TSE-zone in Salvador/Camaçari) become the operational unit; roles renamed to coordinator/advisor/leader with advisors scoped to administered Praças. Leadership is one record per person across many Praças/organizations; vote pledges split leader-declared vs staff-estimated (estimates never serialized to leaders). Adds organizations, demand workflow with staff-only cost/receipts, action-plan results with deputy presence, manual political trend, multi-candidate comparison and the diverging red/white/blue map mode. Migration 20260721_020109_remodel_plazas deliberately resets the campaign vertical in production (public site untouched); test suite ported to the new model (unit 187 / int 306 / e2e 9 green).
56 lines
1.7 KiB
TypeScript
56 lines
1.7 KiB
TypeScript
import type { Payload } from 'payload'
|
|
|
|
import {
|
|
BASELINE_TICKET_2022,
|
|
ELECTION_YEAR_2022,
|
|
FEDERAL_DEPUTY_OFFICE,
|
|
} from '@/lib/electionResults'
|
|
import type { CampaignUser, User } from '@/payload-types'
|
|
import { assertCanReadElectionData } from '@/utilities/campaignAccess'
|
|
|
|
export type FederalCandidateOption = {
|
|
candidateNumber: number
|
|
name: string
|
|
party: string | null
|
|
totalVotesState: number
|
|
}
|
|
|
|
/**
|
|
* Federal-deputy candidates available for comparison (2022 registry ordered by
|
|
* statewide votes). Solla himself is excluded — he is always the reference.
|
|
*/
|
|
export const loadFederalCandidateOptions = async (
|
|
payload: Payload,
|
|
user: CampaignUser | User,
|
|
limit = 60,
|
|
): Promise<FederalCandidateOption[]> => {
|
|
assertCanReadElectionData(user)
|
|
|
|
const result = await payload.find({
|
|
collection: 'electionCandidate',
|
|
where: {
|
|
and: [
|
|
{ year: { equals: ELECTION_YEAR_2022 } },
|
|
{ office: { equals: FEDERAL_DEPUTY_OFFICE } },
|
|
{ turn: { equals: '1' } },
|
|
{ candidateNumber: { not_equals: BASELINE_TICKET_2022.candidate.candidateNumber } },
|
|
// NULL totals sort first on DESC in Postgres — and a candidate without
|
|
// statewide votes is useless as a comparison target anyway.
|
|
{ totalVotesState: { greater_than: 0 } },
|
|
],
|
|
},
|
|
depth: 0,
|
|
limit,
|
|
pagination: false,
|
|
sort: '-totalVotesState',
|
|
select: { candidateNumber: true, urnaName: true, party: true, totalVotesState: true },
|
|
overrideAccess: true,
|
|
})
|
|
|
|
return result.docs.map((candidate) => ({
|
|
candidateNumber: candidate.candidateNumber,
|
|
name: candidate.urnaName,
|
|
party: candidate.party ?? null,
|
|
totalVotesState: candidate.totalVotesState ?? 0,
|
|
}))
|
|
}
|