teqo/src/utilities/nucleusPageData.ts
Francisco Ignácio Fontoura Solla b035cc4a2f Support multi-municipality and multi-neighborhood nucleus territory.
Replace scalar region/city/neighborhood with hasMany arrays so nuclei can span multiple Bahia municipalities while keeping neighborhoods scoped to a single city.
2026-07-18 18:31:51 -03:00

177 lines
4.6 KiB
TypeScript

import type { Payload } from 'payload'
import type { CampaignUser, ElectoralNucleus } from '@/payload-types'
import type { NucleusDetailTab } from '@/utilities/nucleusDetailTabUi'
import {
buildNucleusListWhere,
nucleusPageSize,
parseNucleusListParams,
} from '@/utilities/nucleusUi'
import {
nucleusFormSelect,
nucleusLeadershipDetailSelect,
nucleusListSelect,
nucleusStaffDetailSelect,
toNucleusDetailViewModel,
toNucleusFormViewModel,
} from '@/utilities/nucleusViewModels'
type NucleusListSearchParams = Record<string, string | string[] | undefined>
export class NucleusNotFoundError extends Error {
override name = 'NucleusNotFoundError'
constructor() {
super('Núcleo não encontrado.')
}
}
export type AccessibleNucleusContext = {
id: number
slug: string
document: ElectoralNucleus
}
const nucleusContextSelect = {
name: true,
slug: true,
status: true,
regions: true,
cities: true,
neighborhoods: true,
locality: true,
organizationKind: true,
organizationLabel: true,
tseZones: { zoneNumber: true },
confirmedVoteEstimate: true,
confirmedVoteEstimateAt: true,
confirmedVoteEstimateBy: true,
proposedVoteEstimate: true,
proposedVoteEstimateAt: true,
proposedVoteEstimateBy: true,
proposedVoteEstimateVersion: true,
coordinators: true,
updatedAt: true,
} as const
const nucleusLeadershipContextSelect = {
...nucleusLeadershipDetailSelect,
coordinators: true,
updatedAt: true,
} as const
const getNucleusStaffContextSelect = (activeTab: NucleusDetailTab) => {
if (activeTab === 'overview') {
return {
...nucleusContextSelect,
strengths: nucleusStaffDetailSelect.strengths,
risks: nucleusStaffDetailSelect.risks,
ticketAlliance: nucleusStaffDetailSelect.ticketAlliance,
territoryNotes: nucleusStaffDetailSelect.territoryNotes,
voterProfiles: nucleusStaffDetailSelect.voterProfiles,
primaryContact: nucleusStaffDetailSelect.primaryContact,
} as const
}
if (activeTab === 'territory') {
return {
...nucleusContextSelect,
territoryNotes: nucleusStaffDetailSelect.territoryNotes,
} as const
}
if (activeTab === 'electorate') {
return {
...nucleusContextSelect,
voterProfiles: nucleusStaffDetailSelect.voterProfiles,
} as const
}
if (activeTab === 'leaderships') {
return {
...nucleusContextSelect,
primaryContact: nucleusStaffDetailSelect.primaryContact,
} as const
}
return nucleusContextSelect
}
export const loadNucleusListPageData = async (
payload: Pick<Payload, 'find' | 'count'>,
user: CampaignUser,
searchParams: Promise<NucleusListSearchParams> | NucleusListSearchParams,
) => {
const state = parseNucleusListParams(await searchParams)
const [result, scope] = await Promise.all([
payload.find({
collection: 'electoralNucleus',
depth: 1,
limit: nucleusPageSize,
page: state.page,
sort: 'name',
where: buildNucleusListWhere(state),
select: nucleusListSelect,
user,
overrideAccess: false,
}),
payload.count({
collection: 'electoralNucleus',
where: { status: { equals: 'ativo' } },
user,
overrideAccess: false,
}),
])
return { result, scope, state }
}
export const resolveAccessibleNucleusContext = async (
payload: Pick<Payload, 'find'>,
user: CampaignUser,
nucleusSlug: string,
activeTab: NucleusDetailTab = 'overview',
): Promise<AccessibleNucleusContext> => {
const result = await payload.find({
collection: 'electoralNucleus',
where: { slug: { equals: nucleusSlug } },
depth: 1,
limit: 1,
pagination: false,
select:
user.role === 'lideranca'
? nucleusLeadershipContextSelect
: getNucleusStaffContextSelect(activeTab),
user,
overrideAccess: false,
})
const nucleus = result.docs[0]
if (!nucleus) throw new NucleusNotFoundError()
return {
id: nucleus.id,
slug: nucleus.slug,
document: nucleus as ElectoralNucleus,
}
}
export const getNucleusDetailPageData = (
context: AccessibleNucleusContext,
user: CampaignUser,
) => toNucleusDetailViewModel(context.document, user.role)
export const getNucleusEditPageData = async (
payload: Payload,
user: CampaignUser,
nucleusSlug: string,
) => {
const result = await payload.find({
collection: 'electoralNucleus',
where: { slug: { equals: nucleusSlug } },
depth: 1,
limit: 1,
pagination: false,
select: nucleusFormSelect,
user,
overrideAccess: false,
})
const nucleus = result.docs[0]
if (!nucleus) throw new Error('Núcleo não encontrado.')
return toNucleusFormViewModel(nucleus as ElectoralNucleus)
}