teqo/src/lib/wizardVoteEstimate.ts
Francisco Ignácio Fontoura Solla 625f25c984 B77+: simplify vote wizard helpers after single-screen delivery.
Unify violation highlights with getWizardVoteViolation, share the expected-votes save error constant, and drop dead parseWizardVoteDraft plus unused municipalitySlug prop.
2026-07-30 03:40:20 -03:00

112 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { formatElectionNumber } from '@/lib/electionFormat'
import { MAX_VOTE_COUNT } from '@/lib/schemas/primitives'
import {
getVoteEstimateOrderViolation,
VOTE_ESTIMATE_ORDER_ERROR_MESSAGE,
voteEstimateScenarioLabels,
type VoteEstimateScenario,
type VoteEstimateScenarioViewModel,
} from '@/lib/voteEstimate'
export type VoteShortcut = 'double' | '+50' | '-50' | '+100' | '-100'
export const VOTE_SHORTCUTS: readonly VoteShortcut[] = [
'double',
'+50',
'-50',
'+100',
'-100',
] as const
export const voteShortcutLabels: Record<VoteShortcut, string> = {
double: '2×',
'+50': '+50',
'-50': '−50',
'+100': '+100',
'-100': '−100',
}
export const applyVoteShortcut = (value: number | null, shortcut: VoteShortcut): number => {
const base = value ?? 0
if (shortcut === 'double') {
if (base < 1) return base
return Math.min(base * 2, MAX_VOTE_COUNT)
}
const delta =
shortcut === '+50' ? 50 : shortcut === '-50' ? -50 : shortcut === '+100' ? 100 : -100
return Math.max(0, Math.min(base + delta, MAX_VOTE_COUNT))
}
export type WizardVoteViolation = {
violatingScenario: VoteEstimateScenario
message: string
highlightScenarios: VoteEstimateScenario[]
}
export const getWizardVoteViolation = (
estimates: VoteEstimateScenarioViewModel,
): WizardVoteViolation | null => {
const violatingScenario = getVoteEstimateOrderViolation(estimates)
if (!violatingScenario) return null
return {
violatingScenario,
message: buildWizardVoteViolationMessage(estimates, violatingScenario),
highlightScenarios: resolveWizardVoteHighlights(estimates, violatingScenario),
}
}
const resolveWizardVoteHighlights = (
estimates: VoteEstimateScenarioViewModel,
violatingScenario: VoteEstimateScenario,
): VoteEstimateScenario[] => {
const { pessimistic, central, optimistic } = estimates
if (
violatingScenario === 'central' &&
pessimistic != null &&
central != null &&
pessimistic > central
) {
return ['pessimistic', 'central']
}
if (
violatingScenario === 'optimistic' &&
central != null &&
optimistic != null &&
optimistic < central
) {
return ['optimistic', 'central']
}
return [violatingScenario]
}
const buildWizardVoteViolationMessage = (
estimates: VoteEstimateScenarioViewModel,
violatingScenario: VoteEstimateScenario,
): string => {
const { pessimistic, central, optimistic } = estimates
if (
violatingScenario === 'central' &&
pessimistic != null &&
central != null &&
pessimistic > central
) {
return `${voteEstimateScenarioLabels.pessimistic} (${formatElectionNumber(pessimistic)}) não pode ser maior que ${voteEstimateScenarioLabels.central.toLowerCase()} (${formatElectionNumber(central)}).`
}
if (
violatingScenario === 'optimistic' &&
central != null &&
optimistic != null &&
optimistic < central
) {
return `${voteEstimateScenarioLabels.optimistic} (${formatElectionNumber(optimistic)}) não pode ser menor que ${voteEstimateScenarioLabels.central.toLowerCase()} (${formatElectionNumber(central)}).`
}
return VOTE_ESTIMATE_ORDER_ERROR_MESSAGE
}