Collection actionPlan -> activity (labels "Atividade"/"Atividades"), campo
campaignDemand.actionPlan -> activity, rota /campanha/planos ->
/campanha/atividades (criacao em atividades/nova), sidebar "Atividades" e
rotulos alinhados a entidade ("Tipo de atividade", "Origem da atividade",
"Resultado da atividade"). Valores de enum kind/status/origin inalterados.
Schema movido por migration data-preserving escrita a mao
(20260725_213000_rename_action_plan_to_activity): 4 tabelas, 3 enums, 2
colunas, 39 indices (4 pkeys inclusos), 14 FKs e 2 sequences, cada statement
guardado na existencia do objeto de origem, com down() simetrico. O gerador do
Payload emitiria DROP+CREATE e nao ve o indice parcial escrito a mao
action_plan_upcoming_start_at_idx, entao a lista veio de
pg_indexes/pg_constraint/pg_type/pg_sequences e o snapshot .json foi derivado
do anterior por transformacao textual -- validado por migrate:create __probe
sem mudanca de schema. A mesma migration alinha os 8 indices fosseis %plaza%
que a remodelagem de municipios deixou (renomeou as colunas plaza_id, nao os
indices).
Guard: o describe "banned campaign terminology" de
codebaseConventions.unit.spec.ts virou tabela de termos varrendo src+tests+
scripts (migrations fora -- historia congelada), banindo os compostos
actionPlan, a copy "plano de acao" e a rota antiga, mas nao plan/plano isolado
(colidiria com os planos de assinatura da Fase 2). Allowlist: o proprio spec,
scripts/generate-remodel-municipalities-migration.mjs e o comentario historico
em campaignMigrationReconciliation.int.spec.ts.
Plano: docs/plans/renomear-plano-acao-para-atividade.md
132 lines
4.4 KiB
TypeScript
132 lines
4.4 KiB
TypeScript
import type { Where } from 'payload'
|
|
|
|
import { activityKinds, activityStatuses } from '@/lib/schemas/activity'
|
|
import {
|
|
buildListHref,
|
|
firstValue,
|
|
resolveListUrl,
|
|
strictDecimalInteger,
|
|
type RawSearchParams as CampaignListRawSearchParams,
|
|
} from '@/utilities/campaignListUrl'
|
|
|
|
export const activityPageSize = 25
|
|
|
|
export const activityTabs = ['proximos', 'todos', 'realizados', 'rascunhos'] as const
|
|
export type ActivityTab = (typeof activityTabs)[number]
|
|
|
|
type ActivityKind = (typeof activityKinds)[number]
|
|
export type ActivityStatus = (typeof activityStatuses)[number]
|
|
|
|
export const activityTabLabels: Record<ActivityTab, string> = {
|
|
proximos: 'Próximos',
|
|
todos: 'Todos',
|
|
realizados: 'Realizados',
|
|
rascunhos: 'Rascunhos',
|
|
}
|
|
|
|
export type ActivityListState = {
|
|
page: number
|
|
tab: ActivityTab
|
|
kind?: ActivityKind
|
|
status?: ActivityStatus
|
|
municipality?: number
|
|
}
|
|
|
|
type RawSearchParams = CampaignListRawSearchParams
|
|
|
|
const activityListParamNames = ['tab', 'kind', 'status', 'municipality', 'page'] as const
|
|
|
|
const activityListParamNameSet = new Set<string>(activityListParamNames)
|
|
|
|
const isActivityTab = (value: string | undefined): value is ActivityTab =>
|
|
activityTabs.includes(value as ActivityTab)
|
|
|
|
const isActivityKind = (value: string | undefined): value is ActivityKind =>
|
|
activityKinds.includes(value as ActivityKind)
|
|
|
|
const isActivityStatus = (value: string | undefined): value is ActivityStatus =>
|
|
activityStatuses.includes(value as ActivityStatus)
|
|
|
|
export const parseActivityListParams = (params: RawSearchParams): ActivityListState => {
|
|
const rawPage = strictDecimalInteger(firstValue(params.page))
|
|
const rawTab = firstValue(params.tab)
|
|
const tab = isActivityTab(rawTab) ? rawTab : 'proximos'
|
|
const rawKind = firstValue(params.kind)
|
|
const kind = isActivityKind(rawKind) ? rawKind : undefined
|
|
const rawStatus = tab === 'todos' ? firstValue(params.status) : undefined
|
|
const status = isActivityStatus(rawStatus) ? rawStatus : undefined
|
|
const municipality = strictDecimalInteger(firstValue(params.municipality))
|
|
|
|
return {
|
|
page: rawPage ?? 1,
|
|
tab,
|
|
...(kind ? { kind } : {}),
|
|
...(status ? { status } : {}),
|
|
...(municipality ? { municipality } : {}),
|
|
}
|
|
}
|
|
|
|
export const buildActivityListWhere = (state: ActivityListState, now: Date): Where => {
|
|
const filters: Where[] = []
|
|
|
|
if (state.kind) filters.push({ kind: { equals: state.kind } })
|
|
if (state.municipality) filters.push({ municipality: { equals: state.municipality } })
|
|
|
|
if (state.tab === 'proximos') {
|
|
filters.push({ status: { in: ['planejado', 'confirmado'] } })
|
|
filters.push({ startAt: { greater_than_equal: now.toISOString() } })
|
|
} else if (state.tab === 'realizados') {
|
|
filters.push({ status: { equals: 'realizado' } })
|
|
} else if (state.tab === 'rascunhos') {
|
|
filters.push({ status: { equals: 'rascunho' } })
|
|
} else if (state.status) {
|
|
filters.push({ status: { equals: state.status } })
|
|
}
|
|
|
|
return filters.length ? { and: filters } : {}
|
|
}
|
|
|
|
export const buildActivityListSearchParams = (
|
|
state: ActivityListState,
|
|
page = state.page,
|
|
): URLSearchParams => {
|
|
const canonicalState = parseActivityListParams({
|
|
page: String(page),
|
|
tab: state.tab,
|
|
kind: state.kind,
|
|
status: state.status,
|
|
municipality: state.municipality === undefined ? undefined : String(state.municipality),
|
|
})
|
|
const params = new URLSearchParams()
|
|
|
|
if (canonicalState.tab !== 'proximos') params.set('tab', canonicalState.tab)
|
|
if (canonicalState.kind) params.set('kind', canonicalState.kind)
|
|
if (canonicalState.status) params.set('status', canonicalState.status)
|
|
if (canonicalState.municipality) params.set('municipality', String(canonicalState.municipality))
|
|
if (canonicalState.page > 1) params.set('page', String(canonicalState.page))
|
|
|
|
return params
|
|
}
|
|
|
|
export const buildActivityFiltersKey = (state: ActivityListState): string =>
|
|
buildActivityListSearchParams(state).toString()
|
|
|
|
export const buildActivityListHref = (state: ActivityListState, page: number): string =>
|
|
buildListHref(state, buildActivityListSearchParams, '/campanha/atividades', page)
|
|
|
|
export const resolveActivityListUrl = (
|
|
params: RawSearchParams,
|
|
totalPages?: number,
|
|
): {
|
|
state: ActivityListState
|
|
href: string
|
|
redirectHref?: string
|
|
} =>
|
|
resolveListUrl({
|
|
params,
|
|
paramNameSet: activityListParamNameSet,
|
|
parse: parseActivityListParams,
|
|
buildSearchParams: buildActivityListSearchParams,
|
|
basePath: '/campanha/atividades',
|
|
totalPages,
|
|
})
|