mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-15 10:43:07 +00:00
- Contact.phone (text único) → phones (array field Payload, subcampo value): fonte única; principal = phones[0]; beforeValidate normaliza, filtra vazios, rejeita inválido e duplicado DENTRO da ficha (C111 entre fichas preservado) - migration add_contact_phones_array: backfill phone → phones[0] (gen_random_uuid) antes do drop da coluna + índice em value (hand-edit documentado; snapshot .json gerado mantém as colunas C99/C100 já existentes) - primaryPhoneOf / phoneValuesOf / reorderWithPrimaryPhone em src/lib/phone.ts (ordem = prioridade; inline edit = seta o principal preservando o resto) - findOrCreateContactByPhone aceita phones[] (dedupe pelo primário; reuse faz append dos faltantes; locks em todos os números digitados) - sync conta→ficha (CampaignUser): phone da conta faz APPEND quando a ficha não tem (nunca reordena nem remove); tombstone LGPD substitui TODOS os telefones - convite redemption: telefone digitado vira principal, demais preservados - import CSV: preview sinaliza compartilhado também por número secundário; bulk insere contact_phones (JOIN nas leituras, uuid no insert) - busca por telefone (apoiadores, pickers, combobox) casa qualquer número - UI: PhonesFieldEditor compartilhado (repetível mascarado, remover, ↑/↓, modo inline com Salvar) nas 5 superfícies — liderança (form/ficha/lista), apoiador (form/ficha), dobradinha (ficha), assessor (ficha), wizard - UI pública (petição/WhatsApp) intocada: zod e forms ficam com phone; as ações mapeiam phone → phones[0] - testes: spec novo campaignMultiPhones (aceite completo), specs C111/C99 atualizados, e2e wizard/apoiador ajustados
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import { primaryPhoneOf } from '@/lib/phone'
|
|
import { isPopulatedRelationship } from '@/lib/relationship'
|
|
import type { Contact, Petition } from '@/payload-types'
|
|
import type { ToCSVFunction } from '@payloadcms/plugin-import-export/types'
|
|
|
|
type ExportRow = Record<string, unknown>
|
|
|
|
const emptyContactColumns = (row: ExportRow): void => {
|
|
row.contact_name = ''
|
|
row.contact_email = ''
|
|
row.contact_phone = ''
|
|
row.contact_state = ''
|
|
row.contact_city = ''
|
|
}
|
|
|
|
const isPopulatedPetition = (value: unknown): value is Pick<Petition, 'id' | 'title'> => {
|
|
if (value === null || typeof value !== 'object') return false
|
|
|
|
const record = value as Record<string, unknown>
|
|
return typeof record.id === 'string' && typeof record.title === 'string'
|
|
}
|
|
|
|
export const signatureContactToCSV: ToCSVFunction = ({ value, row }) => {
|
|
if (!isPopulatedRelationship<Contact>(value)) {
|
|
emptyContactColumns(row)
|
|
return undefined
|
|
}
|
|
|
|
row.contact_name = value.name
|
|
row.contact_email = value.email ?? ''
|
|
row.contact_phone = primaryPhoneOf(value.phones) ?? ''
|
|
row.contact_state = value.state ?? ''
|
|
row.contact_city = value.city ?? ''
|
|
return undefined
|
|
}
|
|
|
|
export const signaturePetitionToCSV: ToCSVFunction = ({ value, row }) => {
|
|
if (!isPopulatedPetition(value)) {
|
|
row.petition_id = ''
|
|
row.petition_title = ''
|
|
return undefined
|
|
}
|
|
|
|
row.petition_id = value.id
|
|
row.petition_title = value.title
|
|
return undefined
|
|
}
|