Give coordinators aggregate vote estimates, coverage, and recent updates for the current list filters without leaving /campanha/nucleos.
81 lines
2.1 KiB
TypeScript
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,
|
|
}
|
|
}
|