teqo/src/utilities/nucleusListOverviewViewModels.ts
Francisco Ignácio Fontoura Solla 040c36bed7 Add filtered overview panel to the nuclei list page.
Give coordinators aggregate vote estimates, coverage, and recent updates for the current list filters without leaving /campanha/nucleos.
2026-07-18 18:20:33 -03:00

81 lines
2.1 KiB
TypeScript

import type { CampaignUser, NucleusUpdate } from '@/payload-types'
export const nucleusListOverviewPreviewLimit = 3
export type NucleusListOverviewNucleusRecord = {
id: number
slug: string
name: string
coordinators: Array<number | { id: number }>
confirmedVoteEstimate: number | null
proposedVoteEstimate: number | null
}
export type NucleusListOverviewUpdateRecord = {
id: number
nucleusSlug: string
nucleusName: string
authorName: string
kind: NucleusUpdate['kind']
createdAt: string
}
export type NucleusListOverviewViewModel = {
totalFiltered: number
estimate: {
confirmedTotal: number
confirmedCount: number
confirmedPercent: number
unconfirmedCount: number
pendingSuggestionsCount?: number
}
coverage: {
coordinatedCount: number
percent: number
}
recentUpdates: NucleusListOverviewUpdateRecord[]
}
const percentage = (part: number, total: number): number =>
total === 0 ? 0 : Math.round((part / total) * 100)
export const buildNucleusListOverviewViewModel = ({
nuclei,
recentUpdates,
role,
}: {
nuclei: NucleusListOverviewNucleusRecord[]
recentUpdates: NucleusListOverviewUpdateRecord[]
role: CampaignUser['role']
}): NucleusListOverviewViewModel => {
const totalFiltered = nuclei.length
const confirmedCount = nuclei.filter(
({ confirmedVoteEstimate }) => confirmedVoteEstimate !== null,
).length
const coordinatedCount = nuclei.filter(({ coordinators }) => coordinators.length > 0).length
return {
totalFiltered,
estimate: {
confirmedTotal: nuclei.reduce(
(sum, nucleus) => sum + (nucleus.confirmedVoteEstimate ?? 0),
0,
),
confirmedCount,
confirmedPercent: percentage(confirmedCount, totalFiltered),
unconfirmedCount: totalFiltered - confirmedCount,
...(role === 'lideranca'
? {}
: {
pendingSuggestionsCount: nuclei.filter(
({ proposedVoteEstimate }) => proposedVoteEstimate !== null,
).length,
}),
},
coverage: {
coordinatedCount,
percent: percentage(coordinatedCount, totalFiltered),
},
recentUpdates,
}
}