teqo-backup/src/utilities/homeSearch/loadWizardMunicipalitySuggestions.ts
Cursor Agent dbf6a7fdce
B93 — wizard empty state continuity (visitados + última ação)
Merge client-side recent visits and last-acted municipality storage into
wizard municipality suggest idle list ahead of B92 server rankings.

- Add campaignLastActedMunicipality + wizardMunicipalitySuggestMerge libs
- Extend wizard-municipality-suggest with scopeMunicipalities for hit lookup
- Record last-acted on wizard write success (votes, signal, trend, leadership)
- Clear last-acted on logout alongside recent visits

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
2026-08-01 07:21:56 +00:00

75 lines
2.5 KiB
TypeScript

import 'server-only'
import type { Payload } from 'payload'
import {
toHomeSearchMunicipalityHit,
type WizardMunicipalitySearchSuccessResponse,
} from '@/lib/campaignHomeSearchHits'
import { HOME_SEARCH_STAFF_ONLY_MESSAGE } from '@/lib/campaignHomeSearchMessages'
import { isStaffCampaignRole } from '@/lib/campaignRoles'
import { DEFAULT_VOTE_RANK_YEAR, getMunicipalityVoteRank } from '@/lib/municipalityVoteRank'
import {
rankWizardMunicipalitySuggestions,
type WizardMunicipalitySuggestInput,
} from '@/lib/wizardMunicipalitySuggest'
import type { CampaignUser } from '@/payload-types'
import { loadMunicipalityScope } from '@/utilities/municipality/campaignMunicipalityScope'
import { resolveMunicipalityLastSignalAt } from '@/utilities/municipality/municipalitySignal'
import { computeMunicipalityTerritorialClass } from '@/utilities/municipality/municipalityTerritorialClass'
export const loadWizardMunicipalitySuggestions = async (
payload: Payload,
user: CampaignUser,
): Promise<WizardMunicipalitySearchSuccessResponse> => {
if (!isStaffCampaignRole(user.role)) {
throw new Error(HOME_SEARCH_STAFF_ONLY_MESSAGE)
}
const { municipalities, pledgeAggregates } = await loadMunicipalityScope(
payload,
user,
{},
{
extraSelect: {
lastUpdateAt: true,
engagementLevel: true,
politicalTrend: true,
},
},
)
const inputs: WizardMunicipalitySuggestInput[] = municipalities.map((doc) => {
const aggregate = pledgeAggregates.get(doc.id)
const lastSignalAt = resolveMunicipalityLastSignalAt(
doc.lastUpdateAt ?? null,
aggregate?.lastPledgeAt ?? null,
)
const voteRank = getMunicipalityVoteRank(doc.slug, DEFAULT_VOTE_RANK_YEAR)
return {
slug: doc.slug,
name: doc.name,
lastSignalAt,
engagementLevel: doc.engagementLevel ?? null,
politicalTrend: doc.politicalTrend?.status ?? null,
territorialClass: computeMunicipalityTerritorialClass(doc.slug).class,
votes2022: voteRank?.votes ?? null,
}
})
const ranked = rankWizardMunicipalitySuggestions(inputs)
const docBySlug = new Map(municipalities.map((doc) => [doc.slug, doc]))
return {
status: 'success',
resultKind: 'wizard-suggest',
municipalities: ranked.map((input) => toHomeSearchMunicipalityHit(docBySlug.get(input.slug)!)),
scopeMunicipalities: municipalities.map((doc) => ({
slug: doc.slug,
name: doc.name,
region: doc.region,
priority: doc.priority ?? null,
})),
}
}