150 lines
5.1 KiB
Markdown
150 lines
5.1 KiB
Markdown
# Data Model: Página Sobre
|
||
|
||
**Feature**: 021-pagina-sobre
|
||
**Phase**: 1 — Design & Contracts
|
||
**Status**: Completo
|
||
|
||
---
|
||
|
||
## Nota sobre "Data Model" para feature 100% frontend
|
||
|
||
Esta feature não envolve entidades de banco de dados nem estado gerenciado em store. O "modelo de dados" descreve a estrutura lógica do conteúdo estático e os contratos dos componentes React afetados.
|
||
|
||
---
|
||
|
||
## Componentes — contratos de props
|
||
|
||
### `AboutPage` (novo)
|
||
|
||
| Prop | Tipo | Descrição |
|
||
|------|------|-----------|
|
||
| — | — | Componente sem props (stateless, sem hooks) |
|
||
|
||
**Estrutura JSX de alto nível**:
|
||
|
||
```
|
||
AboutPage
|
||
├── <Navbar />
|
||
├── <main id="main-content" className="min-h-screen bg-canvas">
|
||
│ ├── SectionHero
|
||
│ │ └── título, subtítulo, parágrafo de missão
|
||
│ ├── SectionHistoria
|
||
│ │ └── texto narrativo (2–3 parágrafos)
|
||
│ ├── SectionDiferenciais
|
||
│ │ └── grid de 3–4 DiferencialCard
|
||
│ │ └── { icon, title, description }
|
||
│ ├── SectionNumeros
|
||
│ │ └── grid de 4 MetricCard
|
||
│ │ └── { value, label }
|
||
│ ├── SectionEquipe
|
||
│ │ └── texto introdutório + <Link to="/corretores">
|
||
│ └── SectionCTA
|
||
│ ├── <Link to="/imoveis"> "Ver imóveis disponíveis"
|
||
│ └── <a href="https://wa.me/5500000000000?text=..."> "Falar com corretor"
|
||
└── <Footer />
|
||
```
|
||
|
||
**Tipos locais (apenas internos ao arquivo, não exportados)**:
|
||
|
||
```typescript
|
||
// Apenas para as seções mapeadas com .map()
|
||
|
||
type DiferencialItem = {
|
||
icon: string // emoji ou símbolo UTF-8 (ex.: "🏠")
|
||
title: string
|
||
description: string
|
||
}
|
||
|
||
type MetricItem = {
|
||
value: string // ex.: "10+" | "2.500+" | "98%"
|
||
label: string // ex.: "Anos de mercado"
|
||
}
|
||
```
|
||
|
||
> **Nota**: Os tipos `DiferencialItem` e `MetricItem` NÃO são exportados. São usados somente internamente via arrays locais mapeados por `.map()`. Principle VI: sem abstração prematura.
|
||
|
||
---
|
||
|
||
### `Footer` (alterado)
|
||
|
||
Mudança pontual no array `footerLinks` e no JSX de renderização:
|
||
|
||
**Estado atual**:
|
||
```typescript
|
||
const footerLinks = [
|
||
{ label: 'Imóveis', href: '/imoveis' },
|
||
{ label: 'Sobre', href: '#sobre' }, // ← alterar
|
||
{ label: 'Contato', href: '#contato' },
|
||
{ label: 'Política de Privacidade', href: '/politica-de-privacidade' },
|
||
]
|
||
```
|
||
|
||
**Estado após a feature**:
|
||
```typescript
|
||
// O array footerLinks perde o href de '#sobre'
|
||
// O link "Sobre" passa a ser <Link to="/sobre"> em vez de <a href="#sobre">
|
||
```
|
||
|
||
**Estratégia de implementação no Footer**: O mesmo padrão introduzido pela feature 020 para `/politica-de-privacidade` — o link "Sobre" usa `<Link>` do react-router-dom enquanto os links com `#` permanecem como `<a>`.
|
||
|
||
---
|
||
|
||
### `App.tsx` (alterado)
|
||
|
||
Nova rota pública adicionada ao bloco existente:
|
||
|
||
```typescript
|
||
// Bloco atual (público)
|
||
<Route path="/" element={<HomePage />} />
|
||
<Route path="/imoveis" element={<PropertiesPage />} />
|
||
<Route path="/imoveis/:slug" element={<PropertyDetailPage />} />
|
||
<Route path="/corretores" element={<AgentsPage />} />
|
||
<Route path="/politica-de-privacidade" element={<PrivacyPolicyPage />} />
|
||
|
||
// Nova rota (esta feature)
|
||
<Route path="/sobre" element={<AboutPage />} />
|
||
```
|
||
|
||
---
|
||
|
||
## Conteúdo estático (dados hardcoded em `AboutPage.tsx`)
|
||
|
||
### Diferenciais (3 cards)
|
||
|
||
| Campo | Valor |
|
||
|-------|-------|
|
||
| [1] icon | `🏆` |
|
||
| [1] title | `Experiência comprovada` |
|
||
| [1] description | Mais de 10 anos conectando famílias aos melhores imóveis da região, com histórico de negociações bem-sucedidas. |
|
||
| [2] icon | `🤝` |
|
||
| [2] title | `Atendimento personalizado` |
|
||
| [2] description | Cada cliente é único. Nossa equipe ouve suas necessidades e apresenta opções alinhadas ao seu perfil e orçamento. |
|
||
| [3] icon | `🔑` |
|
||
| [3] title | `Processo transparente` |
|
||
| [3] description | Do primeiro contato à entrega das chaves, mantemos você informado em cada etapa da negociação. |
|
||
|
||
### Números em destaque (4 métricas)
|
||
|
||
| Campo | Valor |
|
||
|-------|-------|
|
||
| [1] value | `10+` |
|
||
| [1] label | Anos de mercado |
|
||
| [2] value | `2.500+` |
|
||
| [2] label | Imóveis negociados |
|
||
| [3] value | `98%` |
|
||
| [3] label | Clientes satisfeitos |
|
||
| [4] value | `30+` |
|
||
| [4] label | Corretores especializados |
|
||
|
||
> **Todos os valores são placeholders** a serem confirmados pelo cliente antes do go-live. Substituição é feita diretamente no array local de `AboutPage.tsx`.
|
||
|
||
---
|
||
|
||
## Contratos de navegação interna
|
||
|
||
| Origem | Destino | Mecanismo | Requisito |
|
||
|--------|---------|-----------|-----------|
|
||
| Footer — link "Sobre" | `/sobre` | `<Link to="/sobre">` | FR-009, FR-012 |
|
||
| CTA Final — "Ver imóveis" | `/imoveis` | `<Link to="/imoveis">` | FR-008, FR-012 |
|
||
| CTA Final — "Falar com corretor" | `https://wa.me/5500000000000?text=...` | `<a href target="_blank" rel="noopener noreferrer">` | FR-008 |
|
||
| Seção Equipe — "Conheça nosso time" | `/corretores` | `<Link to="/corretores">` | FR-007, FR-012 |
|