teqo/src/utilities/activityLeadershipOptions.ts
Francisco Ignácio Fontoura Solla 619666dd51 C13 pos-simplify: fecha os residuos da varredura e estreita os guards
O rename mecanico deixou um defeito silencioso e alguns fosseis: o fixture de
recentVisits perdeu o ${index} (todas as entradas com o mesmo label, invisivel
porque o label nao era asserido) e access/shared.ts guardava "action plan" em
prosa, forma que o guard de vocabulario nao cobria. O padrao agora tolera espaco
e a allowlist encolheu: o comentario de campaignMigrationReconciliation cita
activity e o arquivo saiu da excecao.

Na migration, a entrada action_plan_municipality_idx era inalcancavel (nenhuma
migration jamais criou esse nome) e saiu, deixando up() e down() com os mesmos
48 pares; as duas buscas de FK passam a usar to_regclass, que retorna NULL em vez
de lancar -- a unica consulta que contradizia a invariante do proprio cabecalho.

O detalhe de organizacao para de derivar o rotulo de status a mao e reusa
ActivityStatusBadge, com status tipado como ActivityStatus no loader.

Debitos do /simplify registrados: C8 F4b (o guard de formActions so inspeciona
arquivos chamados exatamente formActions.ts) no plano do C8; defers e descartes
com gatilho no plano do C13.
2026-07-25 21:29:32 -03:00

70 lines
2.1 KiB
TypeScript

import 'server-only'
import type { Payload } from 'payload'
import { isContactSearchQueryReady, normalizeContactSearchQuery } from '@/lib/contactSearchQuery'
import type { CampaignUser, Contact, Leadership } from '@/payload-types'
import { isPopulatedRelationship, relationshipId } from '@/utilities/relationship'
export type ActivityLeadershipOption = {
id: number
label: string
}
const LEADERSHIP_SEARCH_LIMIT = 20
const leadershipLabel = (leadership: Leadership): string | null => {
const id = relationshipId(leadership.id)
if (!id) return null
const contact = leadership.contact
return isPopulatedRelationship<Contact>(contact) ? contact.name : `Liderança #${id}`
}
/**
* Engaged leaderships visible to the actor (for linking an activity to a leadership).
* Uses overrideAccess: false so Payload row-level access applies.
*/
export const searchActivityLeadershipOptions = async (
payload: Pick<Payload, 'find'>,
user: CampaignUser,
query: string,
): Promise<ActivityLeadershipOption[]> => {
const normalizedQuery = typeof query === 'string' ? query : ''
if (!isContactSearchQueryReady(normalizedQuery)) return []
const { trimmed, digits } = normalizeContactSearchQuery(normalizedQuery)
const result = await payload.find({
collection: 'leadership',
where: {
and: [
{ supportStatus: { equals: 'engajado' } },
{
or: [
{ 'contact.name': { contains: trimmed } },
{ 'contact.phone': { contains: digits || trimmed } },
],
},
],
},
depth: 1,
limit: LEADERSHIP_SEARCH_LIMIT,
select: {
contact: true,
supportStatus: true,
},
user,
overrideAccess: false,
})
return result.docs
.map((doc) => {
const leadership = doc as Leadership
const id = relationshipId(leadership.id)
const label = leadershipLabel(leadership)
if (!id || !label) return null
return { id, label }
})
.filter((option): option is ActivityLeadershipOption => option !== null)
.sort((left, right) => left.label.localeCompare(right.label, 'pt-BR'))
}