Página de Contato — Site Público Abracaf
A página de contato (abracaf/contato/page.tsx) é um RSC que compõe um hero, cards de canal de atendimento, formulário interativo e sidebar com mapa, horários e FAQ.
Estrutura da página
page.tsx (RSC)
├── <section> hero navy ← headline + descrição
└── <section> conteúdo
├── CHANNELS (3 cards) ← Associados, Imprensa, Geral
├── ContactForm ← formulário ('use client')
└── sidebar
├── AbracafMapWrapper ← mapa da sede
├── horário ← Seg-Sex, Sáb, Dom
└── FAQ ← accordion com <details>/<summary>
ContactForm
Arquivo: _components/abracaf-contact-form.tsx ('use client')
| Lib | Papel |
|---|---|
react-hook-form | Gerenciamento de estado e submit |
zod + @hookform/resolvers | Validação via ContactSchema |
next-safe-action (useAction) | Chama a server action tipada |
Campos e autoComplete
Todos os campos têm autoComplete declarado para melhorar a UX em mobile e reduzir o atrito de preenchimento:
| Campo | autoComplete | Obrigatório |
|---|---|---|
| Nome | name | Sim |
| Cargo | organization-title | Não |
email | Sim | |
| Telefone | tel | Não |
| Concessionária | organization | Não |
| Tipo de solicitação | — | Sim |
| Mensagem | — | Sim |
| LGPD | — | Sim |
Máscara de telefone
O campo de telefone aplica máscara em tempo real via maskPhone() — uma função pura que formata para (XX) XXXX-XXXX (10 dígitos) ou (XX) XXXXX-XXXX (11 dígitos), sem dependências externas.
Estados do formulário
| Estado | Comportamento |
|---|---|
idle | Formulário disponível para preenchimento |
success | Substitui o formulário por um Alert verde por 5 segundos, depois reseta |
error | Exibe Alert destrutivo no topo do formulário com link de fallback para e-mail |
Server action
Arquivo: _lib/server/contact-abracaf-action.ts
Usa publicActionClient (sem autenticação requerida) do @kit/next/safe-action.
Fluxo de execução
- Recebe
ContactDatavalidado peloContactSchema - Extrai o IP do header
x-forwarded-for(primeiro da lista em caso de proxies) - Verifica o rate limit — lança erro se excedido (ver Rate Limiting)
- Envia o e-mail via
@kit/mailers
Destinatário e fallback de e-mail
const to = process.env.ABRACAF_CONTACT_EMAIL ?? 'secretaria@abracaf.com.br';
Se ABRACAF_CONTACT_EMAIL não estiver definida, os contatos chegam em secretaria@abracaf.com.br. O envio só ocorre se EMAIL_SENDER também estiver definido — em desenvolvimento sem configuração de e-mail, a action retorna sucesso silenciosamente sem tentar enviar.
Variáveis de ambiente
| Variável | Obrigatória | Descrição |
|---|---|---|
EMAIL_SENDER | Sim (prod) | Remetente no formato "Nome <email>" |
ABRACAF_CONTACT_EMAIL | Não | Destinatário; usa fallback se ausente |
FAQ
O FAQ usa <details>/<summary> nativos do HTML sem JavaScript. A seta rotaciona via CSS com group-open:rotate-180 quando o <details> está aberto:
<details className="group py-3">
<summary className="...">
{question}
<span className="transition-transform group-open:rotate-180">▼</span>
</summary>
<p>{answer}</p>
</details>