import type { ActionPlanOrigin } from '@/lib/schemas/actionPlan' import type { ActionPlan, CampaignUser, Contact, Municipality, Organization } from '@/payload-types' import type { ActionPlanDetailTab } from '@/utilities/actionPlanDetailTabUi' import { isPopulatedRelationship, relationshipId } from '@/utilities/relationship' export type ActionPlanMunicipalitySummary = { id: number name: string slug: string } export const actionPlanMunicipalitySummary = ( municipality: ActionPlan['municipality'] | null | undefined, ): ActionPlanMunicipalitySummary | null => isPopulatedRelationship(municipality) ? { id: municipality.id, name: municipality.name, slug: municipality.slug } : null /** Short "where" line, e.g. "Itabuna · Feira do Malhado". */ const formatActionPlanLocationLabel = ({ municipalityName, locality, }: { municipalityName: string | null locality?: string | null }): string => [municipalityName, locality].filter(Boolean).join(' · ') export const actionPlanListSelect = { title: true, slug: true, kind: true, status: true, deputyPresent: true, startAt: true, endAt: true, municipality: true, locality: true, responsible: true, taskDoneCount: true, taskTotal: true, } as const export type ActionPlanListViewModel = { id: number title: string slug: string kind: ActionPlan['kind'] status: ActionPlan['status'] deputyPresent: boolean startAt: string | null endAt: string | null municipalityName: string | null locality: string | null locationLabel: string responsibleName: string | null taskProgress: { done: number; total: number } } const relationshipName = ( relationship: number | Contact | CampaignUser | null | undefined, ): string | null => isPopulatedRelationship(relationship) ? relationship.name : null export const toActionPlanListViewModel = (plan: ActionPlan): ActionPlanListViewModel => { const municipalityName = actionPlanMunicipalitySummary(plan.municipality)?.name ?? null return { id: plan.id, title: plan.title, slug: plan.slug, kind: plan.kind, status: plan.status, deputyPresent: Boolean(plan.deputyPresent), startAt: plan.startAt ?? null, endAt: plan.endAt ?? null, municipalityName, locality: plan.locality ?? null, locationLabel: formatActionPlanLocationLabel({ municipalityName, locality: plan.locality }), responsibleName: relationshipName(plan.responsible), taskProgress: { done: plan.taskDoneCount ?? 0, total: plan.taskTotal ?? 0, }, } } export const actionPlanFormSelect = { title: true, slug: true, kind: true, origin: true, status: true, description: true, deputyPresent: true, startAt: true, endAt: true, deadline: true, municipality: true, locality: true, organizations: true, advisors: true, responsible: true, leadership: true, tasks: true, } as const type ActionPlanFormTaskViewModel = { id: string | null title: string responsible: { id: number; name: string; phone: string | null } | null due: string | null done: boolean } export type ActionPlanFormViewModel = { id: number title: string slug: string kind: ActionPlan['kind'] origin: ActionPlanOrigin status: ActionPlan['status'] description: string | null deputyPresent: boolean startAt: string | null endAt: string | null deadline: string | null municipalityId: number | null locality: string | null organizationIDs: number[] advisorIDs: number[] responsible: { id: number; name: string; phone: string | null } | null leadership: { id: number; label: string } | null tasks: ActionPlanFormTaskViewModel[] } const relationshipIds = (value: unknown): number[] => (Array.isArray(value) ? value : []).map(relationshipId).filter((id): id is number => id !== null) export const toActionPlanFormViewModel = (plan: ActionPlan): ActionPlanFormViewModel => ({ id: plan.id, title: plan.title, slug: plan.slug, kind: plan.kind, origin: plan.origin ?? 'dado', status: plan.status, description: plan.description ?? null, deputyPresent: Boolean(plan.deputyPresent), startAt: plan.startAt ?? null, endAt: plan.endAt ?? null, deadline: plan.deadline ?? null, municipalityId: relationshipId(plan.municipality), locality: plan.locality ?? null, organizationIDs: relationshipIds(plan.organizations), advisorIDs: relationshipIds(plan.advisors), responsible: isPopulatedRelationship(plan.responsible) ? { id: plan.responsible.id, name: plan.responsible.name, phone: plan.responsible.phone ?? null, } : null, leadership: (() => { const leadershipId = relationshipId(plan.leadership) if (!leadershipId) return null if (isPopulatedRelationship(plan.leadership)) { const contact = plan.leadership.contact const contactName = isPopulatedRelationship(contact) ? contact.name : `Liderança #${leadershipId}` return { id: leadershipId, label: contactName } } return { id: leadershipId, label: `Liderança #${leadershipId}` } })(), tasks: (plan.tasks ?? []).map((task) => ({ id: task.id ?? null, title: task.title, responsible: isPopulatedRelationship(task.responsible) ? { id: task.responsible.id, name: task.responsible.name, phone: task.responsible.phone ?? null, } : null, due: task.due ?? null, done: Boolean(task.done), })), }) const actionPlanDetailContextSelect = { title: true, slug: true, kind: true, origin: true, status: true, description: true, deputyPresent: true, startAt: true, endAt: true, deadline: true, municipality: true, locality: true, organizations: true, advisors: true, responsible: true, createdBy: true, updatedAt: true, createdAt: true, } as const export const getActionPlanDetailSelect = (activeTab: ActionPlanDetailTab) => { if (activeTab === 'overview') { return { ...actionPlanDetailContextSelect, taskDoneCount: true, taskTotal: true, resultSummary: true, resultRecordedBy: true, resultRecordedAt: true, } as const } if (activeTab === 'tasks') { return { ...actionPlanDetailContextSelect, tasks: true, } as const } return { ...actionPlanDetailContextSelect, updates: true, } as const } export type ActionPlanTaskViewModel = { id: string | null title: string responsibleId: number | null responsibleName: string | null due: string | null done: boolean doneAt: string | null } export type ActionPlanUpdateViewModel = { id: string | null body: string authorName: string | null createdAt: string | null } type ActionPlanResultViewModel = { summary: string recordedByName: string | null recordedAt: string | null } export type ActionPlanDetailViewModel = { id: number title: string slug: string kind: ActionPlan['kind'] origin: ActionPlanOrigin status: ActionPlan['status'] description: string | null deputyPresent: boolean startAt: string | null endAt: string | null deadline: string | null municipality: ActionPlanMunicipalitySummary | null locality: string | null locationLabel: string organizations: Array<{ id: number; name: string }> advisors: Array<{ id: number; name: string }> responsibleId: number | null responsibleName: string | null taskProgress: { done: number; total: number } tasks: ActionPlanTaskViewModel[] updates: ActionPlanUpdateViewModel[] result: ActionPlanResultViewModel | null createdByName: string | null updatedAt: string createdAt: string } const mapActionPlanTasks = (plan: ActionPlan): ActionPlanTaskViewModel[] => (plan.tasks ?? []).map((task) => ({ id: task.id ?? null, title: task.title, responsibleId: relationshipId(task.responsible), responsibleName: relationshipName(task.responsible), due: task.due ?? null, done: Boolean(task.done), doneAt: task.doneAt ?? null, })) const mapActionPlanUpdates = ( plan: ActionPlan, authorNamesById: ReadonlyMap = new Map(), ): ActionPlanUpdateViewModel[] => (plan.updates ?? []).map((update) => { const authorId = relationshipId(update.author) const populatedName = relationshipName(update.author) return { id: update.id ?? null, body: update.body, authorName: populatedName ?? (authorId ? (authorNamesById.get(authorId) ?? null) : null), createdAt: update.createdAt ?? null, } }) const mapActionPlanResult = (plan: ActionPlan): ActionPlanResultViewModel | null => { const summary = plan.resultSummary?.trim() if (!summary) return null return { summary, recordedByName: relationshipName(plan.resultRecordedBy), recordedAt: plan.resultRecordedAt ?? null, } } export const toActionPlanDetailViewModel = ( plan: ActionPlan, activeTab: ActionPlanDetailTab = 'overview', authorNamesById: ReadonlyMap = new Map(), municipalitySummary: ActionPlanMunicipalitySummary | null = null, ): ActionPlanDetailViewModel => { const municipality = municipalitySummary ?? actionPlanMunicipalitySummary(plan.municipality) return { id: plan.id, title: plan.title, slug: plan.slug, kind: plan.kind, origin: plan.origin ?? 'dado', status: plan.status, description: plan.description ?? null, deputyPresent: Boolean(plan.deputyPresent), startAt: plan.startAt ?? null, endAt: plan.endAt ?? null, deadline: plan.deadline ?? null, municipality, locality: plan.locality ?? null, locationLabel: formatActionPlanLocationLabel({ municipalityName: municipality?.name ?? null, locality: plan.locality, }), organizations: plan.organizations ?.filter((organization): organization is Organization => isPopulatedRelationship(organization), ) .map(({ id, name }) => ({ id, name })) ?? [], advisors: plan.advisors ?.filter((advisor): advisor is CampaignUser => isPopulatedRelationship(advisor), ) .map(({ id, name }) => ({ id, name })) ?? [], responsibleId: relationshipId(plan.responsible), responsibleName: relationshipName(plan.responsible), taskProgress: { done: plan.taskDoneCount ?? 0, total: plan.taskTotal ?? 0, }, tasks: activeTab === 'tasks' ? mapActionPlanTasks(plan) : [], updates: activeTab === 'updates' ? mapActionPlanUpdates(plan, authorNamesById) : [], result: mapActionPlanResult(plan), createdByName: relationshipName(plan.createdBy), updatedAt: plan.updatedAt, createdAt: plan.createdAt, } }