mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
- 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)
76 lines
2.4 KiB
TypeScript
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,
|
|
}))
|
|
}
|