teqo/src/utilities/campaignFormActionError.ts
Francisco Ignácio Fontoura Solla 9fdbae05d7 Add C6 scale/DRY for supporters: bulk import, KPI aggregate, shared shells.
Phase 1 UX: StrictCombobox municipality in SupporterForm, AlertDialog in
RemoveSupporterDataButton. Phase 2 DRY: campaignListUrl + CampaignListPagination
+ campaignFormFields + mapCampaignFormActionError shared across nuclei,
supporters and action plans. Phase 3: single SQL aggregate for supporter list
KPIs via drizzle in the Payload txn. Phase 4: bulk drizzle insert for CSV import
inside the existing Payload txn with ON CONFLICT DO NOTHING, plus a fail-closed
skipContactPhoneInvariant context flag. Phase 5: HMAC-signed single-use import
token backed by a new supporterImportBatch staging collection so the full ok-row
set never crosses the Server Action boundary twice.
2026-07-18 22:17:31 -03:00

40 lines
1.3 KiB
TypeScript

import { ZodError } from 'zod'
import { FormDataBoundaryError, validationFieldErrors } from '@/lib/formData'
export type CampaignFormErrorState<Values> = {
fieldErrors?: Record<string, string[]>
message?: string
values?: Values
revision?: number
}
export type MapCampaignFormActionErrorOptions<Values> = {
error: unknown
safeMessages: readonly string[]
genericMessage: string
values?: Values
revision?: number
resolveBoundaryMessage?: (error: FormDataBoundaryError) => string
}
export const mapCampaignFormActionError = <Values>(
options: MapCampaignFormActionErrorOptions<Values>,
): CampaignFormErrorState<Values> => {
const { error, safeMessages, genericMessage, values, revision, resolveBoundaryMessage } = options
if (error instanceof FormDataBoundaryError) {
const message = resolveBoundaryMessage ? resolveBoundaryMessage(error) : error.message
return { fieldErrors: { [error.field]: [message] }, values, revision }
}
if (error instanceof ZodError) {
return { fieldErrors: validationFieldErrors(error), values, revision }
}
if (
error instanceof Error &&
safeMessages.includes(error.message as (typeof safeMessages)[number])
) {
return { message: error.message, values, revision }
}
return { message: genericMessage, values, revision }
}