Um catálogo de produtos completo (phones, tablets e acessórios) com carrinho de compras, favoritos e tema claro/escuro , construído com React 18 + TypeScript + Vite.
Este projeto é um catálogo de produtos da Apple com funcionalidades completas de e-commerce: listagem com filtros e paginação, página de detalhes com galeria de imagens e seletores de cor/capacidade, carrinho de compras com controle de quantidade, e favoritos. Inclui suporte nativo a tema claro/escuro com persistência via localStorage e detecção automática de preferência do sistema.
Principais Características:
✅ 100% Responsivo (Mobile → Tablet → Desktop)
✅ Tema Claro/Escuro com toggle animado (sol/lua) e persistência
✅ Carrinho de Compras com useReducer e localStorage
✅ Favoritos com persistência local
✅ Busca com Debounce (300ms) integrada à URL
✅ Paginação e Ordenação controlados por URL params
✅ Galeria de Imagens com seletores de cor e capacidade
✅ Slider Automático no banner hero (5s)
✅ Carrossel de Produtos (Hot Prices, Brand New)
✅ React Router v6 com HashRouter e rotas aninhadas
✅ SCSS Modules com CSS Custom Properties para temas
✅ Código Limpo com ESLint (Airbnb), Prettier e Stylelint
Produção: https://glauccoeng-prog.github.io/react_phone-catalog/
🚀 Tecnologias e Ferramentas
Tecnologia
Versão
Descrição
React
18.3.1
Biblioteca de UI com hooks e Context API
TypeScript
5.2
Tipagem estática para JavaScript
Vite
5.3.1
Build tool ultra-rápida com HMR
React Router
6.25.1
Roteamento SPA com HashRouter
SCSS/Sass
1.77.8
Pré-processador CSS com módulos
Tecnologia
Descrição
CSS Modules
Estilos escopados por componente
CSS Custom Properties
Sistema de temas claro/escuro
Mont Font
Tipografia principal (Regular, SemiBold, Bold)
Flexbox / CSS Grid
Layouts flexíveis e responsivos
BEM Naming
Convenção de nomenclatura CSS
Tecnologia
Versão
Descrição
ESLint
8.57.0
Linter JS/TS (config Airbnb + TypeScript)
Prettier
3.3.2
Formatador de código automático
Stylelint
16.7.0
Linter para CSS/SCSS
Tecnologia
Versão
Descrição
Cypress
13.13.0
Testes E2E e de componente
Mochawesome
7.1.3
Relatórios de testes em JSON/HTML
✨ Funcionalidades Implementadas
Toggle animado com ícones SVG inline (sol/lua)
3 fontes de detecção : localStorage → prefers-color-scheme → fallback light
Persistência via localStorage (chave theme)
CSS Custom Properties para transição suave entre temas
Inversão automática de ícones SVG no modo escuro (filter: invert)
Atributo data-no-invert para excluir ícones específicos (ex: coração vermelho)
Paleta dark : botões roxos (#905BFF), superfícies #161827, cards #323542
Adicionar/remover produtos com feedback visual
Controle de quantidade (incrementar/decrementar)
Cálculo automático de total (preço × quantidade)
Persistência em localStorage (chave cart)
Gerenciado com useReducer (ações: ADD, REMOVE, INCREMENT, DECREMENT, CLEAR)
Checkout com dialog de confirmação
Toggle de favorito com ícone de coração (outline/filled)
Persistência em localStorage (chave favorites)
Busca dentro dos favoritos via URL param query
Contador no badge do header
Input com debounce de 300ms para performance
Integrado à URL via useSearchParams
Filtra em tempo real pelo nome do produto
Disponível nas páginas de listagem e favoritos
5. 🖼️ Página de Detalhes do Produto
Galeria de imagens com thumbnails clicáveis
Seletor de cor com 25+ mapeamentos de nome → hex
Seletor de capacidade com links dinâmicos
Seção "About" com descrições renderizadas a partir de array
Tabela de specs (tela, resolução, processador, RAM, câmera, etc.)
"You may also like" com produtos sugeridos aleatoriamente
6. 📊 Listagem com Filtros e Paginação
Ordenação : Mais novos, A-Z, Preço baixo
Itens por página : 4, 8, 16, Todos
Paginação com janela deslizante de 4 páginas visíveis
Todos os parâmetros controlados via URL (sort, perPage, page, query)
Breadcrumbs de navegação
7. 🎠 Sliders e Carrosséis
Banner hero com 4 imagens, auto-play a cada 5s
"Hot Prices" — produtos com maior desconto
"Brand New Models" — produtos mais recentes
Navegação por setas com botões prev/next
Dot indicators no banner
3 breakpoints : Mobile (< 640px), Tablet (640px), Desktop (1200px)
Conteúdo limitado a max-width: 1136px
Header responsivo com menu hamburger mobile
Grids adaptativos para categorias e cards
🏗️ Arquitetura do Projeto
O projeto segue uma arquitetura modular com separação clara de responsabilidades.
┌──────────────┐ ┌────────────────┐ ┌──────────────────────┐
│ HashRouter │────▶│ App.tsx │────▶│ Layout (Header + │
│ (index.tsx) │ │ (Providers) │ │ Outlet + Footer) │
└──────────────┘ └────────────────┘ └──────────────────────┘
│
┌──────────┼──────────┐
▼ ▼ ▼
ThemeProvider CartProvider FavoritesProvider
(useState) (useReducer) (useState)
│ │ │
└──────────┼──────────┘
▼
┌──────────────┐
│ /public/api │ ← JSON estático
│ (fetch + │
│ 300ms delay)│
└──────────────┘
Padrão
Onde
Descrição
Context + Reducer
CartContext
Gerenciamento de estado complexo
Context + State
FavoritesContext, ThemeContext
Estado simples
Barrel Exports
index.ts em cada componente
Re-export para imports limpos
CSS Modules
Todos componentes
Estilos escopados
CSS Custom Properties
_base.scss
Temas sem re-render
URL-driven State
ProductsPage
Sort, page, perPage como URL params
Debounced Input
Header
Otimização de buscas
Lazy Initialization
CartContext
localStorage lido uma única vez
react_phone-catalog/
├── 📄 index.html # HTML principal (entry point)
├── 📄 package.json # Dependências e scripts npm
├── 📄 vite.config.ts # Configuração do Vite
├── 📄 tsconfig.json # Configuração TypeScript
├── 📄 cypress.config.ts # Configuração do Cypress
├── 📄 LICENSE # Licença GPL-3.0
├── 📄 README.md # Esta documentação
│
├── 📁 cypress/ # Testes E2E
│ ├── 📁 integration/
│ │ └── 📄 page.spec.js # Testes da página
│ └── 📁 support/
│ ├── 📄 commands.ts # Comandos customizados
│ ├── 📄 component.ts # Setup de componentes
│ ├── 📄 component-index.html # HTML para component testing
│ └── 📄 e2e.ts # Configuração E2E
│
├── 📁 public/ # Assets estáticos
│ ├── 📁 api/ # JSON API estática
│ │ ├── 📄 products.json # Todos os produtos (listagem)
│ │ ├── 📄 phones.json # Detalhes de phones
│ │ ├── 📄 tablets.json # Detalhes de tablets
│ │ └── 📄 accessories.json # Detalhes de acessórios
│ ├── 📁 fonts/ # Fontes Mont (otf)
│ └── 📁 img/ # Imagens
│ ├── 📁 icons/ # SVG icons (setas, coração, etc.)
│ ├── 📁 phones/ # Fotos por modelo de phone
│ ├── 📁 tablets/ # Fotos por modelo de tablet
│ └── 📁 accessories/ # Fotos por modelo de acessório
│
└── 📁 src/ # Código fonte
│
├── 📄 index.tsx # Entry point (HashRouter + App)
├── 📄 App.tsx # Providers + Routes + Layout
├── 📄 App.scss # Estilos globais da App
├── 📄 vite-env.d.ts # Tipos do Vite
│
├── 📁 styles/ # Estilos globais
│ ├── 📄 _variables.scss # Tokens, fonts, mixins, breakpoints
│ └── 📄 _base.scss # Reset, temas (CSS vars), utilitários
│
├── 📁 types/ # Interfaces TypeScript
│ ├── 📄 Product.ts # Produto (listagem)
│ ├── 📄 ProductDetails.ts # Detalhes do produto
│ └── 📄 CartItem.ts # Item do carrinho
│
├── 📁 utils/
│ └── 📄 api.ts # Funções de fetch (JSON estático)
│
├── 📁 context/ # React Contexts
│ ├── 📄 ThemeContext.tsx # Tema claro/escuro
│ ├── 📄 CartContext.tsx # Carrinho (useReducer)
│ └── 📄 FavoritesContext.tsx # Favoritos (useState)
│
├── 📁 components/ # Componentes reutilizáveis
│ ├── 📁 Header/ # Navegação + busca + badges
│ ├── 📁 Footer/ # Rodapé + back to top
│ ├── 📁 ThemeToggle/ # Botão sol/lua
│ ├── 📁 ProductCard/ # Card de produto
│ ├── 📁 ProductsSlider/ # Carrossel horizontal
│ ├── 📁 PicturesSlider/ # Banner hero auto-play
│ ├── 📁 Pagination/ # Paginação com janela deslizante
│ ├── 📁 Dropdown/ # Select genérico com label
│ ├── 📁 Breadcrumbs/ # Trilha de navegação
│ ├── 📁 BackButton/ # Botão voltar (history)
│ └── 📁 Loader/ # Spinner de carregamento
│
└── 📁 modules/ # Páginas (módulos por rota)
├── 📁 HomePage/ # Página inicial (sliders + categorias)
├── 📁 PhonesPage/ # Listagem de phones
├── 📁 TabletsPage/ # Listagem de tablets
├── 📁 AccessoriesPage/ # Listagem de acessórios
├── 📁 ProductsPage/ # Componente de listagem reutilizável
├── 📁 ProductDetailsPage/ # Detalhes com galeria + specs
├── 📁 FavoritesPage/ # Produtos favoritados
├── 📁 CartPage/ # Carrinho de compras
└── 📁 NotFoundPage/ # Página 404
Paleta de Cores — Tema Claro (Light)
Variável
Valor
Uso
--color-primary
#313237
Textos principais
--color-secondary
#89939A
Textos secundários
--color-icons
#B4BDC3
Ícones
--color-elements
#E2E6E9
Bordas e separadores
--color-hover-and-bg
#FAFBFC
Hover e backgrounds
--color-white
#FFFFFF
Fundo principal
--color-accent
#4219D0
Cor de destaque
--color-button
#313237
Botões CTA
--color-surface
#FFFFFF
Superfície dos cards
Paleta de Cores — Tema Escuro (Dark)
Variável
Valor
Uso
--color-primary
#F1F2F9
Textos principais
--color-secondary
#75767F
Textos secundários
--color-icons
#4A4D58
Ícones
--color-elements
#3B3E4A
Bordas e separadores
--color-hover-and-bg
#323542
Hover e Surface 2
--color-white
#0F1121
Fundo principal (Gray-Black)
--color-accent
#905BFF
Cor de destaque (Roxo)
--color-button
#905BFF
Botões CTA (Roxo)
--color-surface
#161827
Superfície dos cards
Propriedade
Valor
Font Family
Mont, Arial, sans-serif
Font Weights
400 (Regular), 600 (SemiBold), 700 (Bold)
Font Size (base)
14px
Line Height (base)
21px
Variável
Valor
Dispositivo
Base
< 640px
Mobile (padrão)
$tablet
640px
Tablets
$desktop
1200px
Desktop
Propriedade
Valor
Max Width
1136px
Padding Mobile
16px
Padding Tablet
24px
Padding Desktop
48px
Componentes Reutilizáveis
Componente
Arquivo
Descrição
Header
components/Header/
Nav + busca debounced + badges + menu mobile
Footer
components/Footer/
Links + "Back to top" smooth scroll
ThemeToggle
components/ThemeToggle/
Toggle claro/escuro com SVG animado
ProductCard
components/ProductCard/
Card com preços, specs, cart e favorito
ProductsSlider
components/ProductsSlider/
Carrossel com setas (Hot Prices, Brand New)
PicturesSlider
components/PicturesSlider/
Banner hero com auto-play 5s + dots
Pagination
components/Pagination/
Paginação com janela de 4 páginas
Dropdown
components/Dropdown/
Select nativo com label
Breadcrumbs
components/Breadcrumbs/
Trilha Home > Categoria > Produto
BackButton
components/BackButton/
Navegação history.back()
Loader
components/Loader/
Spinner CSS animado
Mixin
Descrição
Uso
on-tablet
Media query ≥ 640px
@include on-tablet { ... }
on-desktop
Media query ≥ 1200px
@include on-desktop { ... }
content-padding-inline
Padding lateral responsivo
@include content-padding-inline;
Rota
Componente
Descrição
/
HomePage
Banner, sliders Hot Prices/Brand New, categorias
/phones
PhonesPage → ProductsPage
Listagem de phones com filtros
/tablets
TabletsPage → ProductsPage
Listagem de tablets com filtros
/accessories
AccessoriesPage → ProductsPage
Listagem de acessórios com filtros
/product/:productId
ProductDetailsPage
Galeria, specs, cor, capacidade, sugestões
/favorites
FavoritesPage
Produtos favoritados com busca
/cart
CartPage
Carrinho com quantidades e checkout
*
NotFoundPage
Página 404
Nota: PhonesPage, TabletsPage e AccessoriesPage são wrappers finos que renderizam ProductsPage com a categoria correspondente.
🧠 Gerenciamento de Estado
Context
Padrão
Persistência
Funcionalidades
ThemeContext
useState
localStorage("theme")
theme, toggleTheme()
CartContext
useReducer
localStorage("cart")
addToCart, removeFromCart, increment, decrement, clearCart, isInCart, totalItems, totalPrice
FavoritesContext
useState
localStorage("favorites")
toggleFavorite, isFavorite, totalFavorites, favorites[]
<HashRouter>
<ThemeProvider> ← Tema (data-theme no <html>)
<CartProvider> ← Carrinho (useReducer)
<FavoritesProvider> ← Favoritos (useState)
<Routes />
</FavoritesProvider>
</CartProvider>
</ThemeProvider>
</HashRouter>
Função
Descrição
getProducts()
Retorna todos os produtos (products.json)
getPhones()
Retorna detalhes dos phones (phones.json)
getTablets()
Retorna detalhes dos tablets (tablets.json)
getAccessories()
Retorna detalhes dos acessórios (accessories.json)
getProductDetails(id)
Busca nas 3 categorias e retorna o produto por id
getSuggestedProducts()
Retorna produtos embaralhados aleatoriamente
Todas as funções possuem simulação de delay de 300ms para UX realista.
O projeto utiliza Cypress para testes end-to-end e de componentes.
Configuração (cypress.config.ts)
e2e : {
baseUrl : 'http://localhost:3000' ,
specPattern : 'cypress/integration/**/*.spec.{js,ts,jsx,tsx}' ,
} ,
component : {
framework : 'react' ,
bundler : 'vite' ,
} ,
video : true ,
viewportHeight : 1920 ,
viewportWidth : 1080 ,
reporter : 'mochawesome' ,
# Modo interativo (abre navegador)
npm run test
# Apenas testes (sem lint)
npm run test -- --only
Node.js v20 ou superior
npm v9 ou superior
# 1. Clone o repositório
git clone https://github.com/glauccoeng-prog/react-phone-catalog.git
cd react-phone-catalog
# 2. Instale as dependências
npm install
# 3. Inicie o servidor de desenvolvimento
npm start
# 4. Acesse no navegador
# http://localhost:3000
# Gerar build otimizado
npm run build
# Deploy para GitHub Pages
npm run deploy
Script
Comando
Descrição
npm start
mate-scripts start -l
Inicia servidor de desenvolvimento
npm run build
mate-scripts build
Gera build de produção
npm run deploy
mate-scripts deploy
Deploy para GitHub Pages
npm run lint
style-format + format + lint-js + lint-css
Executa todos os linters
npm run lint-js
mate-scripts lint -j
Lint JavaScript/TypeScript
npm run lint-css
mate-scripts lint -s
Lint CSS/SCSS
npm run format
prettier --write
Formata arquivos TS/TSX
npm run style-format
stylelint --fix
Corrige estilos SCSS
npm run test
mate-scripts test -l
Lint + testes Cypress
Este projeto foi implementado baseado nos designs do Figma:
Home — Banner slider + Hot Prices + Shop by Category + Brand New
Phones/Tablets/Accessories — Listagem com filtros, sort e paginação
Product Details — Galeria + seletores + specs + "You may also like"
Favorites — Lista de favoritos com busca
Cart — Itens, quantidades, total e checkout
404 — Página não encontrada
Este projeto está sob a licença GPL-3.0 . Veja o arquivo LICENSE para mais detalhes.
Glaucco Siqueira
Desenvolvido com 💚 durante o curso da Mate Academy