feat: features 025-032 - favoritos, contatos, trabalhe-conosco, area-cliente, navbar, hero-light-dark, performance-homepage
Some checks failed
CI/CD → Deploy via SSH / Build & Push Docker Images (push) Successful in 1m0s
CI/CD → Deploy via SSH / Deploy via SSH (push) Successful in 4m35s
CI/CD → Deploy via SSH / Validate HTTPS & Endpoints (push) Failing after 46s

- feat(025): favoritos locais com FavoritesContext, HeartButton, PublicFavoritesPage
- feat(026): central de contatos admin (leads/contatos unificados)
- feat(027): configuração da página de contato via admin
- feat(028): trabalhe conosco - candidaturas com upload e admin
- feat(029): UX área do cliente - visitas, comparação, perfil
- feat(030): navbar UX - menu mobile, ThemeToggle, useFavorites
- feat(031): hero light/dark - imagens separadas por tema, upload, preview, seed
- feat(032): performance homepage - Promise.all parallel fetches, sessionStorage cache,
  preload hero image, loading=lazy nos cards, useInView hook, will-change carrossel,
  keyframes em index.css, AgentsCarousel e HomeScrollScene via props
- fix: light mode HomeScrollScene - gradiente, cores de texto, scroll hint

migrations: g1h2i3j4k5l6 (source em leads), h1i2j3k4l5m6 (contact_config),
            i1j2k3l4m5n6 (job_applications), j2k3l4m5n6o7 (hero theme images)
This commit is contained in:
MatheusAlves96 2026-04-22 22:35:17 -03:00
parent 6ef5a7a17e
commit cf5603243c
106 changed files with 11927 additions and 1367 deletions

View file

@ -0,0 +1,203 @@
# Feature Specification: Revisão UX/UI — Área do Cliente
**Feature Branch**: `029-ux-area-do-cliente`
**Created**: 2026-04-22
**Status**: Draft
---
## User Scenarios & Testing *(mandatory)*
### User Story 1 — Navegar direto para Favoritos ao acessar a Área do Cliente (Priority: P1)
O cliente autenticado digita ou clica no link da Área do Cliente e chega imediatamente à lista de imóveis favoritos, sem passar por uma tela de painel intermediária que não agrega valor.
**Why this priority**: Elimina um clique desnecessário presente hoje. É a mudança de maior impacto imediato na jornada do usuário e desbloqueio para todo o restante da área.
**Independent Test**: Acessar `/area-do-cliente` deve redirecionar para `/area-do-cliente/favoritos`. A página de Favoritos deve carregar de forma autônoma e ser completamente utilizável.
**Acceptance Scenarios**:
1. **Given** um cliente autenticado, **When** ele acessa `/area-do-cliente`, **Then** é redirecionado automaticamente para `/area-do-cliente/favoritos`.
2. **Given** um cliente autenticado, **When** ele acessa `/area-do-cliente/boletos`, **Then** recebe uma resposta 404 (rota inexistente).
3. **Given** um cliente autenticado, **When** ele visualiza o menu lateral, **Then** os itens "Painel" e "Boletos" não estão presentes.
---
### User Story 2 — Visualizar favoritos com imagem, preço e localização (Priority: P1)
O cliente vê seus imóveis favoritos exibidos em cards que mostram a thumbnail da propriedade, o preço e a cidade/bairro, permitindo identificar cada imóvel sem precisar clicar para abrir.
**Why this priority**: É a página mais acessada da área do cliente. Sem imagem e preço, o usuário não consegue distinguir os imóveis e a experiência é frustrante.
**Independent Test**: Com ao menos um favorito salvo, a página deve exibir cards com imagem (ou placeholder), preço formatado e localização.
**Acceptance Scenarios**:
1. **Given** um cliente com favoritos salvos, **When** ele acessa `/area-do-cliente/favoritos`, **Then** cada card exibe thumbnail da propriedade (ou placeholder se sem foto), título, preço e cidade/bairro.
2. **Given** um cliente sem favoritos, **When** ele acessa a página, **Then** vê um empty state informativo com link para `/imoveis`.
3. **Given** um cliente visualizando favoritos, **When** ele clica em "Ver imóvel", **Then** é levado à página de detalhes do imóvel.
4. **Given** um cliente visualizando favoritos, **When** ele remove um favorito, **Then** o card some da lista sem recarregar a página.
---
### User Story 3 — Cancelar visita agendada (Priority: P2)
O cliente pode solicitar o cancelamento de uma visita com status pendente diretamente pela Área do Cliente, sem precisar entrar em contato por outro canal.
**Why this priority**: Resolve um ponto de atrito real: hoje o usuário não tem como cancelar uma visita pelo sistema, o que gera contato desnecessário via WhatsApp ou telefone.
**Independent Test**: Com uma visita no status "pendente", o botão "Cancelar" deve ser exibido e, ao clicar, alterar o status para "cancelado".
**Acceptance Scenarios**:
1. **Given** uma visita com `status=pending`, **When** o cliente acessa `/area-do-cliente/visitas`, **Then** o card exibe o botão "Cancelar".
2. **Given** o cliente clica em "Cancelar", **When** a ação é confirmada, **Then** o status do card muda para "cancelado" e o botão desaparece.
3. **Given** uma visita com status diferente de `pending` (ex: confirmada, cancelada), **When** o cliente visualiza o card, **Then** o botão "Cancelar" não está disponível.
4. **Given** uma falha de rede ao cancelar, **When** a requisição retorna erro, **Then** o cliente vê uma mensagem de erro e o status não muda.
---
### User Story 4 — Editar perfil e trocar senha (Priority: P2)
O cliente pode acessar `/area-do-cliente/conta`, visualizar seus dados cadastrais, atualizar o nome e alterar a senha, tudo dentro da Área do Cliente.
**Why this priority**: Hoje não existe nenhuma forma do cliente atualizar seus dados pelo sistema. É uma funcionalidade básica esperada em qualquer área logada.
**Independent Test**: A página `/area-do-cliente/conta` deve existir com formulário funcional de atualização de nome e de troca de senha.
**Acceptance Scenarios**:
1. **Given** o cliente acessa `/area-do-cliente/conta`, **When** a página carrega, **Then** exibe o nome atual preenchido e o e-mail em campo somente leitura.
2. **Given** o cliente altera o nome e clica em "Salvar", **When** o nome é válido (não vazio), **Then** vê confirmação de sucesso e o nome atualizado no menu lateral.
3. **Given** o cliente preenche "Senha atual", "Nova senha" e "Confirmar nova senha", **When** as senhas coincidem e têm pelo menos 8 caracteres, **Then** a senha é alterada e uma mensagem de sucesso é exibida.
4. **Given** o cliente informa uma senha atual incorreta, **When** submete o form, **Then** vê mensagem de erro "Senha atual incorreta" sem alterar nada.
5. **Given** "Nova senha" e "Confirmar nova senha" divergem, **When** o cliente tenta salvar, **Then** vê validação inline "As senhas não coincidem" antes de enviar ao servidor.
---
### User Story 5 — Navegação com ícones consistentes e item "Minha conta" (Priority: P3)
O cliente vê o menu lateral (desktop) e a barra de navegação (mobile) com ícones vetoriais consistentes em qualquer sistema operacional, e um link "Minha conta" que leva à nova página de perfil.
**Why this priority**: Melhoria visual e de consistência; não bloqueia funcionalidades principais, mas impacta a percepção de qualidade do produto.
**Independent Test**: O menu deve renderizar 4 itens (Favoritos, Comparar, Visitas, Minha conta) com ícones SVG visíveis e corretos em temas claro e escuro.
**Acceptance Scenarios**:
1. **Given** o cliente está na Área do Cliente, **When** visualiza o menu lateral ou a barra mobile, **Then** os 4 itens (Favoritos, Comparar, Visitas, Minha conta) estão presentes com ícones SVG.
2. **Given** o cliente está em qualquer página da área do cliente, **When** observa o item de menu correspondente à página atual, **Then** o item está visualmente destacado (ativo).
3. **Given** o cliente está em mobile, **When** acessa a barra de navegação, **Then** os 4 itens estão centralizados sem scroll horizontal desnecessário.
4. **Given** o cliente clica em "Sair", **When** a ação é executada, **Then** o ícone do botão é o ícone de logout (seta saindo de uma porta), não uma seta genérica.
---
### User Story 6 — Empty state explicativo no Comparar (Priority: P3)
O cliente que acessa a página de comparação sem imóveis selecionados recebe uma instrução clara sobre como adicionar imóveis à comparação.
**Why this priority**: Melhoria de usabilidade pontual; sem ela o usuário fica confuso, mas o impacto é menor que os itens anteriores.
**Independent Test**: Acessar `/area-do-cliente/comparar` sem imóveis selecionados deve exibir o empty state com a instrução de uso.
**Acceptance Scenarios**:
1. **Given** o cliente não tem imóveis na comparação, **When** acessa `/area-do-cliente/comparar`, **Then** vê uma mensagem explicando como adicionar imóveis (ex: "Acesse um imóvel e clique em 'Comparar' para adicioná-lo aqui").
2. **Given** o cliente tem imóveis na comparação, **When** acessa a página, **Then** a tabela de comparação é exibida normalmente.
---
### Edge Cases
- O que acontece se a foto de um imóvel favorito for removida após ser salvo? → O card exibe um placeholder de imagem.
- O que acontece se o cliente tentar cancelar uma visita já cancelada por outra aba? → O servidor retorna erro e o frontend exibe mensagem informativa.
- O que acontece se o cliente enviar o form de perfil com nome vazio? → Validação inline impede o envio antes de chegar ao servidor.
- O que acontece se o cliente sem favoritos tentar acessar diretamente `/area-do-cliente`? → Redireciona para `/area-do-cliente/favoritos` e exibe o empty state de favoritos.
- O que acontece se a sessão expirar durante uso da área do cliente? → O cliente é redirecionado para a tela de login com mensagem de sessão expirada.
---
## Requirements *(mandatory)*
### Functional Requirements
**Roteamento e Estrutura**
- **FR-001**: O sistema DEVE redirecionar `/area-do-cliente` para `/area-do-cliente/favoritos` de forma automática.
- **FR-002**: A rota `/area-do-cliente/boletos` DEVE ser removida; acessá-la DEVE retornar 404.
- **FR-003**: O menu de navegação da Área do Cliente DEVE conter exatamente 4 itens: Favoritos, Comparar, Visitas e Minha conta.
- **FR-004**: Os ícones do menu DEVE ser SVG vetoriais (Heroicons 2.0 outline), sem uso de emoji ou caracteres Unicode.
**Favoritos**
- **FR-005**: Cada card de favorito DEVE exibir: thumbnail da propriedade (ou placeholder padronizado), título, preço formatado em reais e cidade/bairro.
- **FR-006**: A thumbnail DEVE ser obtida a partir dos dados da propriedade (campo `cover_photo` ou primeira foto da galeria).
- **FR-007**: O card DEVE oferecer as ações "Ver imóvel" (navega para detalhe) e "Remover dos favoritos" (remove sem recarregar a página).
**Visitas**
- **FR-008**: O card de visita DEVE exibir: título do imóvel em destaque, data agendada/solicitada em destaque, badge de status alinhado à direita e mensagem como texto secundário.
- **FR-009**: Visitas com `status=pending` DEVE exibir botão "Cancelar".
- **FR-010**: Ao confirmar o cancelamento, o sistema DEVE chamar `PATCH /me/visits/:id/cancel` e atualizar o status do card para "cancelado" sem recarregar a página.
- **FR-011**: Visitas com status diferente de `pending` NÃO DEVEM exibir o botão "Cancelar".
**Comparar**
- **FR-012**: Quando não há imóveis selecionados para comparação, a página DEVE exibir um empty state com instrução clara de como adicionar imóveis à comparação.
**Perfil / Minha conta**
- **FR-013**: A rota `/area-do-cliente/conta` DEVE ser criada e acessível pelo menu "Minha conta".
- **FR-014**: A página de conta DEVE exibir o nome atual do cliente em campo editável e o e-mail em campo somente leitura.
- **FR-015**: O cliente DEVE poder atualizar o nome via `PATCH /me/profile`; o campo nome é obrigatório.
- **FR-016**: O cliente DEVE poder trocar a senha informando senha atual, nova senha e confirmação via `PATCH /me/password`.
- **FR-017**: A nova senha DEVE ter no mínimo 8 caracteres; a confirmação DEVE ser idêntica à nova senha; validações DEVEM ocorrer no frontend antes do envio.
- **FR-018**: Se a senha atual informada estiver incorreta, o servidor DEVE retornar erro e o frontend DEVE exibir "Senha atual incorreta".
**Backend — Novos Endpoints**
- **FR-019**: `PATCH /me/profile` — atualiza o nome do cliente autenticado. Requer autenticação JWT. Retorna os dados atualizados.
- **FR-020**: `PATCH /me/password` — altera a senha do cliente autenticado. Valida senha atual antes de persistir. Requer autenticação JWT.
- **FR-021**: `PATCH /me/visits/:id/cancel` — cancela uma visita com `status=pending` pertencente ao cliente autenticado. Retorna a visita atualizada. Requer autenticação JWT.
- **FR-022**: Tentativa de cancelar visita com status diferente de `pending` DEVE retornar erro com mensagem descritiva.
- **FR-023**: Tentativa de cancelar visita de outro cliente DEVE retornar 403 Forbidden.
**Layout e Mobile**
- **FR-024**: O botão "Sair" DEVE usar o ícone ArrowRightOnRectangle (Heroicons) no lugar do caractere `→`.
- **FR-025**: Em viewport mobile, a barra de navegação DEVE centralizar os 4 itens e indicar visualmente o item ativo.
### Key Entities
- **ClientUser**: Usuário da área do cliente. Atributos relevantes: `id`, `name`, `email`, `password_hash`. Possui coleções de favoritos e visitas.
- **SavedProperty (Favorito)**: Associação entre `ClientUser` e `Property`. Atributos relevantes: `id`, `client_user_id`, `property_id`, `created_at`.
- **VisitRequest (Visita)**: Solicitação de visita feita por um `ClientUser` para uma `Property`. Atributos relevantes: `id`, `client_user_id`, `property_id`, `scheduled_date`, `status` (pending | confirmed | cancelled), `message`.
- **Property (Imóvel)**: Imóvel do catálogo. Atributos consumidos nesta feature: `id`, `title`, `price`, `city`, `neighborhood`, `cover_photo` (ou galeria de fotos).
---
## Success Criteria *(mandatory)*
### Measurable Outcomes
- **SC-001**: O cliente chega ao conteúdo real (Favoritos) com um clique a menos do que hoje — a página de painel não existe mais como etapa intermediária.
- **SC-002**: O cliente consegue identificar visualmente seus imóveis favoritos sem precisar abrir nenhum deles — cada card mostra imagem, preço e localização.
- **SC-003**: O cliente consegue cancelar uma visita pendente em menos de 3 cliques a partir da página de Visitas, sem sair da Área do Cliente.
- **SC-004**: O cliente consegue atualizar nome ou senha em uma única interação com o formulário de conta, sem precisar entrar em contato com suporte.
- **SC-005**: Os ícones do menu são renderizados de forma idêntica em Windows, macOS e Linux, tanto em tema claro quanto escuro.
- **SC-006**: A taxa de abandono da Área do Cliente (saída imediata) deve ser reduzida, dado que o primeiro conteúdo exibido passa a ser imediatamente útil.
- **SC-007**: Todos os 3 novos endpoints do backend respondem corretamente com autenticação válida e retornam erros descritivos para entradas inválidas.
---
## Assumptions
- A tabela `client_users` já existe no banco com as colunas `id`, `name`, `email` e `password_hash`; nenhuma migration de schema é necessária para os endpoints de perfil e senha.
- A tabela `visit_requests` já possui a coluna `status` com os valores `pending`, `confirmed` e `cancelled`; o endpoint de cancelamento apenas atualiza este campo.
- O backend de favoritos já expõe o `property_id`; a foto do imóvel será obtida do campo `cover_photo` da tabela de propriedades ou do primeiro item retornado pela API de fotos já existente.
- O sistema de autenticação JWT para clientes já está operacional; os novos endpoints reutilizarão o mesmo middleware de autenticação.
- A remoção de `BoletosPage` é apenas frontend e de rota; o model e os dados de boletos no banco são mantidos intactos para uso futuro pelo admin.
- O componente de comparação já armazena os imóveis selecionados em estado local ou contexto; esta feature não altera o mecanismo de seleção, apenas o empty state.
- Não há requisito de confirmação por e-mail para troca de senha nesta fase (fluxo simplificado: validar senha atual → salvar nova senha).
- A feature não inclui upload de foto de perfil do cliente.