teqo/src/utilities/campaignInvitePageData.ts
Francisco Ignácio Fontoura Solla bcac665cb5 Ship /campanha nuclei MVP with RBAC, invites, and vote estimates.
Adds electoral nuclei, leaderships, updates, and WhatsApp invite flows behind campaign auth, plus the consolidated schema migration that Vercel applies on deploy.
2026-07-18 15:01:56 -03:00

104 lines
2.9 KiB
TypeScript

import 'server-only'
import type { Payload } from 'payload'
import type { Consent, Leadership } from '@/payload-types'
import type { CampaignInviteKind } from '@/utilities/campaignInvite'
import { getLeadershipConsent } from '@/utilities/campaignConsent'
import { findActiveCampaignInvite } from '@/utilities/campaignInviteRepository'
import { relationshipId } from '@/utilities/relationship'
type CampaignInviteProfile = {
name: string
phone: string
email: string | null
gender: 'feminino' | 'masculino' | 'outro' | 'nao_informado' | null
sector: Leadership['sector'] | null
sectorNotes: string | null
}
export type CampaignInvitePageData =
| { status: 'invalid' }
| {
status: 'valid'
kind: CampaignInviteKind
profile: CampaignInviteProfile
requiresConsent: boolean
consentData: Consent['text']
}
const invalidInvite = (): CampaignInvitePageData => ({ status: 'invalid' })
export const getCampaignInviteConsentState = async (
payload: Payload,
): Promise<{ configured: boolean }> => ({
configured: Boolean(await getLeadershipConsent(payload)),
})
export const getCampaignInvitePageData = async (
payload: Payload,
token: string,
): Promise<CampaignInvitePageData> => {
if (token.length < 20 || token.length > 256) return invalidInvite()
try {
const invite = await findActiveCampaignInvite(payload, token)
const leadershipID = relationshipId(invite?.leadership)
if (!invite || leadershipID === null) return invalidInvite()
const leadership = await payload.findByID({
collection: 'leadership',
id: leadershipID,
depth: 0,
select: {
contact: true,
sector: true,
sectorNotes: true,
supportStatus: true,
consent: true,
consentContentHash: true,
},
overrideAccess: true,
})
if (invite.kind === 'login' && leadership.supportStatus !== 'engajado') {
return invalidInvite()
}
const contactID = relationshipId(leadership.contact)
if (contactID === null) return invalidInvite()
const [contact, consent] = await Promise.all([
payload.findByID({
collection: 'contact',
id: contactID,
depth: 0,
select: {
name: true,
phone: true,
email: true,
gender: true,
},
overrideAccess: true,
}),
getLeadershipConsent(payload),
])
if (!consent) return invalidInvite()
return {
status: 'valid',
kind: invite.kind,
profile: {
name: contact.name,
phone: contact.phone,
email: contact.email ?? null,
gender: contact.gender ?? null,
sector: leadership.sector ?? null,
sectorNotes: leadership.sectorNotes ?? null,
},
requiresConsent:
relationshipId(leadership.consent) !== consent.id ||
leadership.consentContentHash !== consent.contentHash,
consentData: consent.text,
}
} catch {
return invalidInvite()
}
}