teqo-backup/src/lib/campaignQuickActionDemands.ts
Francisco Solla 212a1f2423 feat(campaign): C87 — atualização unificada (texto + polaridade + urgente)
Substitui o modelo de MunicipalityUpdate (kind/semanal/urgente/nota/sinal + signalType)
por um modelo unificado: body obrigatório + polarity (boa/neutra/ruim) + urgent + adversarySignal.

- Schema: polarity enum obrigatório, urgent boolean default false, adversarySignal boolean
- Wizard: novo WizardUpdateBodyStep com campo de texto + polaridade + urgente
- Lista: controle unificado de atualização com polaridade inline
- Feed: exibe polaridade como badge colorido + indicador de urgência
- V2 status strip: atualização rápida de polaridade
- E11: queries atualizadas para polarity + adversarySignal
- Migração: 20260807_030000_unify_municipality_update (backfill polarity=neutra, urgent de kind, adversarySignal de kind+signalType)
- Testes: 18/18 integração C87, 593/593 total, 1399/1399 unitários
- Fix: testes de state deputy usavam nomes fixos que colidiam entre execuções
2026-08-07 05:04:41 -03:00

104 lines
3 KiB
TypeScript
Raw Permalink 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 {
CAMPAIGN_WIZARD_ACTION_SLUGS,
wizardActionHref,
type CampaignWizardActionId,
} from '@/lib/campaignActionRoutes'
import { homeActionsForRole } from '@/lib/campaignHomeActions'
import { CAMPAIGN_DEMANDS_HOME } from '@/lib/campaignPaths'
import type { CampaignQuickActionContext } from '@/lib/campaignQuickActionContext'
import { isListPath } from '@/lib/campaignQuickActionPaths'
import type { CampaignQuickAction } from '@/lib/campaignQuickActionTypes'
import { isStaffCampaignRole, type CampaignRole } from '@/lib/campaignRoles'
export const CAMPAIGN_DEMANDS_CREATE_HREF = `${CAMPAIGN_DEMANDS_HOME}/nova` as const
const DETAIL_WIZARD_ACTION_IDS: readonly CampaignWizardActionId[] = [
'update-votes',
'register-update',
'change-trend',
'update-leadership',
'register-demand',
]
export const demandCreateHref = (municipalityId?: number): string => {
if (municipalityId === undefined) {
return CAMPAIGN_DEMANDS_CREATE_HREF
}
return `${CAMPAIGN_DEMANDS_CREATE_HREF}?municipality=${municipalityId}`
}
export const isDemandsListPath = (pathname: string): boolean =>
isListPath(pathname, CAMPAIGN_DEMANDS_HOME)
export const isDemandDetailPath = (pathname: string): boolean => {
if (!pathname.startsWith(`${CAMPAIGN_DEMANDS_HOME}/`)) {
return false
}
const rest = pathname.slice(`${CAMPAIGN_DEMANDS_HOME}/`.length)
if (!rest || rest.includes('/')) {
return false
}
return rest !== 'nova'
}
const registerDemandListAction = (role: CampaignRole): CampaignQuickAction | null => {
const source = homeActionsForRole(role).find((action) => action.id === 'register-demand')
if (!source) {
return null
}
return {
...source,
href: CAMPAIGN_DEMANDS_CREATE_HREF,
}
}
/** B85 list: single "Registrar pedido" launcher (form route — wizard A5 is still a stub). */
export const resolveDemandsListQuickActions = (
role: CampaignRole,
): readonly CampaignQuickAction[] => {
if (!isStaffCampaignRole(role)) {
return []
}
const action = registerDemandListAction(role)
return action ? [action] : []
}
/** B85 detail: staff Início A1–A5 with municipality prefill when linked. */
export const resolveDemandDetailQuickActions = (
role: CampaignRole,
context: CampaignQuickActionContext,
returnPath: string,
): readonly CampaignQuickAction[] => {
if (!isStaffCampaignRole(role)) {
return []
}
const { municipalitySlug, municipalityId } = context
if (!municipalitySlug) {
return []
}
const byId = new Map(homeActionsForRole(role).map((action) => [action.id, action]))
return DETAIL_WIZARD_ACTION_IDS.flatMap((id) => {
const action = byId.get(id)
if (!action) {
return []
}
if (id === 'register-demand') {
return [
{
...action,
href: demandCreateHref(municipalityId),
},
]
}
return [
{
...action,
href: wizardActionHref(CAMPAIGN_WIZARD_ACTION_SLUGS[id], municipalitySlug, {
returnPath,
}),
},
]
})
}