teqo-backup/src/utilities/electionCandidateOptions.ts
Francisco Ignácio Fontoura Solla cf6ae6c47c Pass 2 W2: correcoes de fronteira lib/utilities e client boundary
- helpers puros movidos utilities->lib: slug, phone, wordStartFilter, voteEstimate (9 inversoes lib->utilities zeradas)
- chaves de consent em src/lib/campaignConsentKeys.ts (client-safe); campaignInvite/campaignConsent re-exportam; onda0ConsentTexts referencia as constantes
- 'server-only' em 21 loaders Payload/cache (CLI segue com --conditions=react-server)
- ciclo de tipos supporterListFilters <-> supporterUi quebrado (SupporterListFilterInput estrutural; sqlFilters idem)
- votePledgeData dividido: votePledgeViews (puro, client-safe) + votePledgeData (loaders, server-only) - padrao contract-module
- predicados de role client-safe em src/lib/campaignRoles.ts; access/shared deriva deles (fonte unica); nav.ts para de importar o barrel campaignAccess (casts 'as CampaignUser' eliminados)
2026-07-25 14:38:41 -03:00

76 lines
2.4 KiB
TypeScript

import 'server-only'
import configPromise from '@payload-config'
import { unstable_cache } from 'next/cache'
import { getPayload } 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'
import { ELECTION_TSE_CACHE_TAG } from '@/utilities/electionCache'
export type FederalCandidateOption = {
candidateNumber: number
name: string
party: string | null
totalVotesState: number
}
/** Cross-request cached core — immutable 2022 registry, busted with `election-tse`. */
const loadFederalCandidateOptionsCached = unstable_cache(
async (limit: number): Promise<FederalCandidateOption[]> => {
const payload = await getPayload({ config: configPromise })
return queryFederalCandidateOptions(limit, payload)
},
['federal-candidate-options'],
{ tags: [ELECTION_TSE_CACHE_TAG] },
)
/**
* Federal-deputy candidates available for comparison (2022 registry ordered by
* statewide votes). Solla himself is excluded — he is always the reference.
*/
export const loadFederalCandidateOptions = (
user: CampaignUser | User,
limit = 60,
): Promise<FederalCandidateOption[]> => {
assertCanReadElectionData(user)
return loadFederalCandidateOptionsCached(limit)
}
const queryFederalCandidateOptions = async (
limit: number,
payload: Awaited<ReturnType<typeof getPayload>>,
): Promise<FederalCandidateOption[]> => {
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,
}))
}