teqo/src/lib/schemas/votePledge.ts
Francisco Ignácio Fontoura Solla 4806c417c8 Engineering Pass 3: consolidate patterns and lock them with guards.
Fold duplicated campanha access, loaders, list/filter/form shells, and scripts into shared modules; reorganize utilities by domain; stabilize e2e; and document prevention-first audit workflow so the same smells cannot creep back in.
2026-07-29 06:11:29 -03:00

67 lines
2.3 KiB
TypeScript

import { z } from 'zod'
import {
MAX_VOTE_COUNT,
positiveRelationshipId,
trimmedNullableText,
} from '@/lib/schemas/primitives'
import {
getVoteEstimateOrderViolation,
VOTE_ESTIMATE_ORDER_ERROR_MESSAGE,
} from '@/lib/voteEstimate'
const optionalEstimate = z.number().int().min(0).max(MAX_VOTE_COUNT).nullable().optional()
export const voteEstimateScenarioFieldsSchema = z
.object({
pessimistic: optionalEstimate,
central: optionalEstimate,
optimistic: optionalEstimate,
})
.superRefine((value, ctx) => {
const violation = getVoteEstimateOrderViolation(value)
if (violation) {
ctx.addIssue({
code: 'custom',
message: VOTE_ESTIMATE_ORDER_ERROR_MESSAGE,
path: [violation],
})
}
})
/** Staff declare votes on behalf of a linked leadership in one municipality. */
export const declareVotesSchema = z.object({
municipality: positiveRelationshipId,
leadership: positiveRelationshipId,
declaredVotes: z.number().int().min(0).max(MAX_VOTE_COUNT),
})
/** Staff record their internal estimate for one pledge. */
export const estimateVotesSchema = z.object({
pledge: positiveRelationshipId,
estimatedVotes: voteEstimateScenarioFieldsSchema,
estimateNote: trimmedNullableText(1000),
})
/**
* Refusal messages matched by exact string in the routes' `safeMessages` —
* same exact-string contract as `STATE_DEPUTY_STAFF_MESSAGE`: a literal at
* either end is one reword away from silently collapsing into the generic
* error, so the conventions spec bans literals at both ends.
*/
export const VOTE_PLEDGE_DECLARE_STAFF_MESSAGE =
'Somente a coordenação e a assessoria registram votos declarados.'
export const VOTE_PLEDGE_LEADERSHIP_REQUIRED_MESSAGE = 'Informe a liderança da declaração.'
export const VOTE_PLEDGE_MUNICIPALITY_NOT_LINKED_MESSAGE =
'A liderança precisa estar vinculada ao município para registrar votos declarados nele.'
export const VOTE_PLEDGE_ESTIMATE_STAFF_MESSAGE =
'Somente a coordenação, a assessoria e o candidato registram estimativas.'
export const VOTE_PLEDGE_DECLARE_SAFE_MESSAGES = [
VOTE_PLEDGE_DECLARE_STAFF_MESSAGE,
VOTE_PLEDGE_MUNICIPALITY_NOT_LINKED_MESSAGE,
VOTE_PLEDGE_LEADERSHIP_REQUIRED_MESSAGE,
] as const
export type DeclareVotesInput = z.input<typeof declareVotesSchema>
export type EstimateVotesInput = z.input<typeof estimateVotesSchema>