# ContactForm

> Componentes / Formulário e ação · Estado: **Em andamento** — Implementado e utilizável, mas ainda sem a validação completa de acessibilidade.

O formulário-padrão de contato, sobre as primitivas (E73): nome, e-mail, telefone, assunto (opcional), mensagem e o aceite de privacidade e contato (E154), em FormField, com o resumo de erros no topo quando o envio falha e a tela de sucesso em `role="status"`.

- Função: Formulário e ação
- Também chamado de: fale conosco, formulário de contato, contato
- Mora em: `app/components/organisms/marketing/ContactForm.tsx`
- Página: [https://phorte-design-system.vercel.app/styleguide/peca/ContactForm](https://phorte-design-system.vercel.app/styleguide/peca/ContactForm)
- Ficha no Storybook: [marketing-contactform](https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/marketing-contactform--docs)
- Prévia ao vivo, sozinha: [https://phorte-design-system.vercel.app/previa/ContactForm/0](https://phorte-design-system.vercel.app/previa/ContactForm/0)
- Todas as peças: [https://phorte-design-system.vercel.app/llms.txt](https://phorte-design-system.vercel.app/llms.txt)

## Como usar no código

```tsx
import { ContactForm } from '@/app/components/organisms/marketing/ContactForm';

<ContactForm />
```

## Uso

### Variantes na ficha

1. [Padrão](https://phorte-design-system.vercel.app/previa/ContactForm/0)
2. [Com os links do aceite](https://phorte-design-system.vercel.app/previa/ContactForm/1)

Em página que precisa de um canal de contato genérico — e como o modelo de formulário que as equipes clonam.

### Quando não usar

Para só captar e-mail, a Newsletter ou a NewsletterStrip. Para conversa ao vivo, o ChatWindow.

### Faça

- Passe `onEnviar`: ele recebe `{ nome, email, telefone, assunto, mensagem, aceite }` — o telefone só em dígitos, com o DDD — e, no segundo argumento, os sinais de spam (E153). Sem ele, o formulário **simula** o envio (1,5s) — é a vitrine do padrão.
- Leia os sinais no serviço que recebe (E153): com `campoIscaPreenchido`, descarte; com `rapidoDemais` (menos de `tempoMinimo`, 3s por padrão), marque para revisão em vez de descartar.
- Escreva cada erro dizendo como acertar: "Informe um e-mail com @ e domínio".
- Marque o que não é obrigatório com "(opcional)", como o Assunto.
- Passe `hrefDaPolitica` e `hrefDosTermos`: o aceite cita os dois, e os links abrem em nova aba — quem está no meio do formulário não perde o que escreveu.

### Evite

- Voltar para a validação do navegador: ela fala a língua do sistema e não liga o erro ao campo.
- Avisar na tela que o envio parece spam: o robô aprende o que foi pego. O formulário segue o fluxo de sempre; quem decide é o serviço.
- Deixar o aceite marcado de saída, ou juntar nele uma autorização que não seja para responder a mensagem (LGPD: o consentimento é da pessoa, e por finalidade).
- Máscara no telefone: ela briga com quem cola o número e com o leitor de tela. O formulário aceita como a pessoa escreve e limpa no envio.

### Anatomia

1. **Resumo de erros** — Quando o envio falha: "Há N problemas no formulário", com um link para cada campo (padrão GOV.UK), `role="alert"`, que recebe o foco.
2. **Nome e e-mail** — FormField obrigatórios com o Input, `autocomplete="name"` e `"email"`. O rótulo é "E-mail" (era "E-mail corporativo", E154).
3. **Telefone** — FormField obrigatório com o Input `type="tel"` e `autocomplete="tel"` (E154), a dica "Com DDD." visível; aceita parênteses, traço, espaço e +55, e valida 10 ou 11 dígitos.
4. **Assunto** — FormField "(opcional)" com o Select e a sugestão "Selecione o motivo do contato", ao lado do telefone a partir do tablet.
5. **Mensagem** — FormField obrigatório com o Textarea.
6. **Aceite** — Grupo "Privacidade e contato" (FormField `as="fieldset"`) com o Checkbox `aceite`, desmarcado: "Li e aceito a Política de Privacidade e os Termos de Uso, e autorizo a Faculdade Phorte a responder pelo e-mail e pelo telefone informados" (E154).
7. **Enviar** — Button primário grande, com o ícone de envio.
8. **Campo-isca** — Proteção contra spam (E153): um campo fora da tela e `inert` — fora do Tab e da árvore de acessibilidade —, que só robô preenche. Com o tempo de preenchimento, vira os sinais do envio.
9. **Sucesso** — `role="status"`: o visto, "Mensagem enviada!" (que recebe o foco) e "Enviar nova mensagem".

### Estados

| Estado | O que muda |
| --- | --- |
| Erro | O resumo no topo e, em cada campo, o erro em pt-BR embaixo, `aria-invalid` e a borda vermelha — conferido no teste da ficha. |
| Enviando | O Button em `isLoading` ("Enviando mensagem…" para o leitor), `aria-busy`, focável. |
| Enviado | A tela de sucesso, com o foco no título (E102). |
| Sem o aceite | A caixa vermelha vazia; no envio, o erro do grupo e o link no resumo, que leva à caixa (E154). |

### Comportamento

| Situação | O que acontece |
| --- | --- |
| Enviar com campos faltando | Não envia; o resumo aparece com o foco, e cada link leva ao campo — conferido no teste da ficha. |
| Enviar completo | Chama `onEnviar` (ou simula) e mostra o sucesso com o foco no título — conferido no teste da ficha. |
| "Enviar nova mensagem" | Limpa o formulário, recomeça o relógio da proteção contra spam e devolve o foco ao primeiro campo (E102). |
| Envio de robô | Campo-isca preenchido ou envio antes do tempo mínimo: o formulário segue igual, e os sinais acesos vão para `onEnviar` — conferido no teste da ficha. |

### Relacionados

- [FormField](https://phorte-design-system.vercel.app/styleguide/md/FormField.md) — O campo com rótulo, dica e erro.
- [Textarea](https://phorte-design-system.vercel.app/styleguide/md/Textarea.md) — A mensagem.
- [Newsletter](https://phorte-design-system.vercel.app/styleguide/md/Newsletter.md) — Para só captar e-mail.

## Especificação

### Propriedades

| Prop | Tipo | Padrão | Obrigatória | Descrição |
| --- | --- | --- | --- | --- |
| `onEnviar` | `(dados: DadosDeContato, sinais: SinaisDeSpam) => void \| Promise<void>` | — | não | Recebe os dados e envia (E73). Sem ela, o formulário **simula** o envio (1,5s) — é a vitrine do padrão de formulário, e a E102 construiu em cima dela o caminho do foco. O segundo argumento são os sinais de spam (E153): o campo-isca e o tempo de preenchimento. O formulário não bloqueia nada — quem decide é o serviço que recebe (ver `app/lib/protecao-contra-spam.tsx`). |
| `tempoMinimo` | `number` | — | não | Tempo mínimo de preenchimento, em ms, para o sinal de "rápido demais" (E153). Padrão: 3000. |
| `hrefDaPolitica` | `string` | — | não | Os endereços da Política de Privacidade e dos Termos de Uso, que o aceite cita (E154). Abrem em nova aba: quem está no meio do formulário não perde o que escreveu. Sem eles, o texto do aceite fica sem link. |
| `hrefDosTermos` | `string` | — | não |  |

### Tokens de cor

| Token | Valor | Usado como |
| --- | --- | --- |
| `--background` | #FAFAFA | `bg-background` |
| `--border` | #E5E5E5 | `border-border` |
| `--foreground` | #1A1A1A | `text-ink` |
| `--muted-foreground` | #595959 | `text-muted-foreground` |
| `--primary` | #D42B2B | `text-primary` |

## Acessibilidade

### Teclado

| Tecla | Faz |
| --- | --- |
| Tab | Passa pelos links do resumo (se houver), por nome, e-mail, telefone, assunto, mensagem, a caixa do aceite e os links dele, e Enviar. O campo-isca fica fora (E153). |
| Espaço | Na caixa do aceite, marca e desmarca. |
| Enter | Num link do resumo, leva ao campo; no botão, envia. |
| ↑ / ↓ | No Assunto, as teclas do `<select>`. |

### Leitor de tela

- Cada erro fica ligado ao campo pelo FormField; o resumo é `role="alert"` e recebe o foco a cada envio que falha.
- O sucesso é `role="status"` com o foco no título: quem usa leitor de tela ouve que enviou.
- Os links do aceite terminam com "(abre em nova aba)" para quem ouve, e o nome do Checkbox é o texto inteiro do aceite — conferido no teste da ficha.

### O que sustenta o estado

Usa os padrões: formulario, regiaoViva. Falta ouvir com leitor de tela: formulario, regiaoViva.

## Status e recursos

| Tipo | Recurso | Status |
| --- | --- | --- |
| Código | `app/components/organisms/marketing/ContactForm.tsx` | Disponível |
| Ficha | https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/marketing-contactform--docs | Disponível |
| Teste de acessibilidade | axe em `npm run test` | No gate de todo commit |
| Leitor de tela | Passada da E33 | Falta ouvir |
| Design | Figma | Desativado até a Fase 2 |

### Histórico

- `251416b` 2026-10-01 — E159: Testimonials — o vídeo toca dentro do cartão, YouTube e Vimeo
- Histórico completo no GitHub: https://github.com/srbunnie/Pos-Phorte-Design-System/commits/main/app/components/organisms/marketing/ContactForm.tsx
