teqo-backup/src/collections/Subscription.ts
Francisco Solla 398a91e54a feat(S9): captura de novidades da campanha na home pública (form + CTA do hero)
Seção 'Receba as novidades da campanha' acima do rodapé: nome + WhatsApp
obrigatórios, e-mail/estado/cidade/comentário opcionais, toggle pré-selecionado
'Quero fazer parte do time' gravado como subscription.campaignLevel
(time|esporadico). CTA secundário do hero vira o atalho (#novidades, scroll
suave). Contact + Subscription em withPayloadTransaction com consentimento
novo fail-closed por chave estável 'campanha-novidades' — nada é gravado sem o
texto aprovado no admin. Migration 20260819_192605 (state de contact nullable
+ coluna campaign_level). Impl plan, changelog, int + e2e.
2026-08-20 02:19:58 +00:00

59 lines
1.7 KiB
TypeScript

import { payloadAdminOnly } from '@/utilities/campaignAccess'
import { CollectionConfig } from 'payload'
export const Subscription: CollectionConfig = {
slug: 'subscription',
labels: {
singular: 'Assinatura',
plural: 'Assinaturas',
},
admin: {
group: 'Contatos',
defaultColumns: ['contact', 'consent', 'campaignLevel', 'comment'],
},
// Citizen PII. Public opt-in flows write via the Local API without a user
// (overrideAccess defaults to true), so admin-only access does not affect them.
access: {
create: payloadAdminOnly,
read: payloadAdminOnly,
update: payloadAdminOnly,
delete: payloadAdminOnly,
},
fields: [
{
type: 'relationship',
name: 'contact',
label: 'Contato',
required: true,
relationTo: 'contact',
},
{
type: 'relationship',
name: 'consent',
label: 'Consentimento',
required: true,
relationTo: 'consent',
},
{
name: 'comment',
type: 'textarea',
label: 'Comentario',
maxLength: 1000,
},
{
// S9 — the campaign home capture records the visitor's engagement
// choice ("Quero fazer parte do time" vs "esporádico") as data, so the
// admin can tell who may join WhatsApp groups. Nullable on purpose: the
// WhatsApp community flow writes subscriptions without it; only the
// campaign newsletter schema sets it (zod-required).
name: 'campaignLevel',
type: 'select',
label: 'Nível de engajamento',
required: false,
options: [
{ label: 'Fazer parte do time', value: 'time' },
{ label: 'Comunicações esporádicas', value: 'esporadico' },
],
},
],
}