teqo/src/utilities/demand/campaignDemandFormData.ts
Francisco Solla 2cc8f2c14d feat(C143): demandas visíveis apenas para responsáveis explícitos + candidato/coordenador
- campaignDemand.responsibles (hasMany → campaignUser, staff elegível) com
  hook beforeValidate que descarta ids não-staff (fail-closed)
- canRead/UpdateCampaignDemand por membership: assessor só vê demandas onde
  é responsável; unrestricted/admin sempre; leader nunca (fim do escopo
  municipal de demandas)
- criador entra automaticamente como responsável no hook de criação (form,
  wizard, rascunhos C90); migration com backfill created_by_id → responsável
- UI: picker multi-select na criação (nova + wizard) e card de gestão no
  detalhe com save full-replace + advisory lock; sugestões = assessores do
  município; rótulo 'Visível para: Responsáveis · Candidato · Coordenador'
- int tests reescritos para a regra nova + 5 casos novos; e2e novo de
  visibilidade (lista/URL/gestão); fixture e2e com createCampaignDemand
- impl plan + changelog; importMap regenerado com S3_* dummy (OPS69)
2026-08-19 23:55:07 -03:00

28 lines
1.1 KiB
TypeScript

import {
nullableRelationshipFormValue,
repeatedRelationshipFormValues,
requiredFormText,
requiredRelationshipFormValue,
} from '@/lib/formData'
import { campaignDemandKinds, type CampaignDemandKind } from '@/lib/schemas/campaignDemand'
import type { CampaignDemandCreateInput } from '@/lib/schemas/campaignDemandInput'
/**
* Shared create-form parsing for the two demand cadastros (wizard step and
* `/demandas/nova`): same free-text field, kind coercion and municipality /
* activity relationships — the actions only differ in the response wrapper.
*/
export const parseCampaignDemandCreateFormData = (
formData: FormData,
): CampaignDemandCreateInput => {
const rawKind = requiredFormText(formData, 'kind')
return {
kind: campaignDemandKinds.includes(rawKind as CampaignDemandKind)
? (rawKind as CampaignDemandKind)
: 'outro',
description: requiredFormText(formData, 'description'),
municipality: requiredRelationshipFormValue(formData, 'municipalityId'),
activity: nullableRelationshipFormValue(formData, 'activityId') ?? undefined,
responsibles: repeatedRelationshipFormValues(formData, 'responsibles'),
}
}