{"id":29028099,"url":"https://github.com/vidigal-code/challenge-pokeapi-angular","last_synced_at":"2025-06-26T07:05:34.660Z","repository":{"id":300069411,"uuid":"1004972074","full_name":"Vidigal-code/challenge-PokeAPI-Angular","owner":"Vidigal-code","description":"challenge-PokeAPI-Angular","archived":false,"fork":false,"pushed_at":"2025-06-19T17:39:09.000Z","size":52,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-19T18:44:18.721Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Vidigal-code.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-19T13:11:04.000Z","updated_at":"2025-06-19T17:39:12.000Z","dependencies_parsed_at":"2025-06-19T18:57:24.103Z","dependency_job_id":null,"html_url":"https://github.com/Vidigal-code/challenge-PokeAPI-Angular","commit_stats":null,"previous_names":["vidigal-code/challenge-pokeapi-angular"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Vidigal-code/challenge-PokeAPI-Angular","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vidigal-code%2Fchallenge-PokeAPI-Angular","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vidigal-code%2Fchallenge-PokeAPI-Angular/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vidigal-code%2Fchallenge-PokeAPI-Angular/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vidigal-code%2Fchallenge-PokeAPI-Angular/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Vidigal-code","download_url":"https://codeload.github.com/Vidigal-code/challenge-PokeAPI-Angular/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vidigal-code%2Fchallenge-PokeAPI-Angular/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262018772,"owners_count":23245622,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-26T07:05:33.938Z","updated_at":"2025-06-26T07:05:34.646Z","avatar_url":"https://github.com/Vidigal-code.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pokédex App 📱🔍\n\n## Descrição em Português\n\nEste projeto é uma aplicação mobile e web híbrida desenvolvida com **Ionic + Angular + TypeScript + TailwindCSS**, consumindo a [PokeAPI](https://pokeapi.co/).  \nA tela principal exibe uma lista paginada de Pokémons com nome e imagem, e redireciona para uma tela de detalhes com informações adicionais.  \nImplementei **injeção de dependência** com os serviços Angular (`@Injectable`), facilitando testes e reaproveitamento de lógica.  \nUtilizei **componentização Angular** com módulos e rotas organizadas para escalabilidade e separação de responsabilidades.  \nA interface é **responsiva e adaptativa**, aproveitando os recursos do **Ionic Framework** e estilos personalizados com **TailwindCSS**.  \nUsuários podem marcar Pokémons como **favoritos**, que são salvos localmente usando o `Storage` do Ionic.  \nSegui boas práticas de versionamento com **commits semânticos**, **nomes claros** e estrutura de código modular.  \nImplementei **pipes e diretivas customizadas** para otimizar o carregamento e formatação dos dados.  \nA aplicação está preparada para **modo retrato e paisagem**, com experiência fluida em dispositivos móveis e tablets.  \nO projeto está disponível no GitHub, incluindo **imagens, GIFs demonstrativos** e testes com **Karma + Jasmine**.\n\n---\n\n## English Description\n\nThis project is a hybrid mobile and web app built using **Ionic + Angular + TypeScript + TailwindCSS**, consuming the [PokeAPI](https://pokeapi.co/).  \nThe main screen displays a paginated list of Pokémon with names and images, and redirects to a detail screen with additional data.  \nI implemented **dependency injection** using Angular services (`@Injectable`) to improve testability and logic reuse.  \nAngular **component and module structure** ensures scalability and proper separation of concerns.  \nThe interface is **responsive and adaptive**, leveraging **Ionic Framework** and custom styling via **TailwindCSS**.  \nUsers can mark Pokémon as **favorites**, stored locally using Ionic's `Storage` service.  \nI followed clean code practices with **semantic commits**, **clear naming**, and modular code architecture.  \nCustom **pipes and directives** help optimize data formatting and performance.  \nThe app adapts to both **portrait and landscape modes**, offering a smooth experience across phones and tablets.  \nThe GitHub repo includes **screenshots, demo GIFs**, and unit tests using **Karma + Jasmine**.\n\n---\n\n## 📦 Project Demonstration\n\nCheck out the live demo of the project:\n\n- 🔗 [View on GitHub Pages](https://vidigal-code.github.io/challenge-PokeAPI-Angular/#/)\n\n\u003e ℹ️ Make sure the URL includes `/#/` since the app uses hash-based routing for GitHub Pages compatibility.\n\n---\n\n## 📹 Demonstration Video\n\nCheck out the demonstration video:\n\n- [Youtube](https://www.youtube.com/watch?v=foadnlqKipg)\n\n---\n\n### 🖼️ Layout\n\n**🔍 Version Desktop:**\n\n![Example-PokeAPI-Desktop](example/Example-PokeAPI-Desktop.gif)\n\n---\n\n**📱 Version Mobile:**\n\n![Example-PokeAPI-Mobile](example/Example-PokeAPI-Mobile.gif)\n\n---\n\n### 🧪 Test - Example\n\n**Angular Test:**\n\n![angular-test](example/angular-test.png)\n\n**Angular Test Page:**\n\n![page-angular-test](example/page-angular-test.png)\n\n\n\n---\n\n#### Backend (Custom WebHook Server)\n\n![webhook-server-example](example/webhook-server-example.png)\n\n\n---\n\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/25.png\" width=\"150\" alt=\"Pikachu\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Uma aplicação web e mobile moderna para explorar o mundo dos Pokémons, construída com Ionic, Angular, e TailwindCSS.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Angular-DD0031?style=for-the-badge\u0026logo=angular\u0026logoColor=white\" alt=\"Angular\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Ionic-3880FF?style=for-the-badge\u0026logo=ionic\u0026logoColor=white\" alt=\"Ionic\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Node.js-339933?style=for-the-badge\u0026logo=nodedotjs\u0026logoColor=white\" alt=\"Node.js\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Tailwind_CSS-38B2AC?style=for-the-badge\u0026logo=tailwind-css\u0026logoColor=white\" alt=\"Tailwind CSS\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License: MIT\"\u003e\n\u003c/p\u003e\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePortuguês 🇧🇷 (Clique para expandir)\u003c/strong\u003e\u003c/summary\u003e\n\n## 📜 Índice\n\n- [Sobre o Projeto](#-sobre-o-projeto)\n- [✨ Funcionalidades](#-funcionalidades)\n- [🛠️ Tecnologias Utilizadas](#️-tecnologias-utilizadas)\n- [🏛️ Arquitetura e Boas Práticas](#️-arquitetura-e-boas-práticas)\n- [🪝 Implementação de WebHook (Diferencial)](#-implementação-de-webhook-diferencial)\n- [🧪 Testes Unitários (Diferencial)](#-testes-unitários-diferencial)\n- [🚀 Como Executar o Projeto](#-como-executar-o-projeto)\n- [📁 Estrutura de Arquivos](#-estrutura-de-arquivos)\n- [☁️ Deploy](#️-deploy)\n- [👨‍💻 Autor](#-autor)\n\n## 📖 Sobre o Projeto\n\nEste projeto é uma Pokédex moderna e responsiva desenvolvida como uma aplicação híbrida (web/mobile) utilizando o poder do **Ionic** e **Angular**. Ele consome a [PokeAPI](https://pokeapi.co/) para fornecer uma lista paginada e pesquisável de Pokémons, com uma tela de detalhes rica em informações para cada criatura.\n\nO projeto foi construído seguindo as melhores práticas de desenvolvimento, com foco em código limpo, componentização, reutilização de lógica e uma arquitetura escalável.\n\n## ✨ Funcionalidades\n\n-   **Listagem e Paginação:** Navegue por uma lista completa de Pokémons com um sistema de paginação eficiente.\n-   **Busca Dinâmica:** Encontre Pokémons rapidamente por nome ou número, com `debounce` para otimizar a performance.\n-   **Tela de Detalhes Completa:** Veja informações detalhadas como tipos, habilidades, estatísticas, habitat e múltiplos sprites.\n-   **Sistema de Favoritos:** Marque seus Pokémons preferidos! A lista é salva localmente (`localStorage`) para persistir entre as sessões.\n-   **Página de Favoritos Dedicada:** Gerencie sua coleção de favoritos em uma tela separada, com busca e paginação próprias.\n-   **Design Responsivo:** A interface se adapta perfeitamente a qualquer dispositivo, seja celular (retrato/paisagem) ou desktop, graças ao TailwindCSS.\n-   **Notificações de WebHook:** Ações na lista de favoritos (adicionar, remover, limpar) enviam notificações em tempo real para um servidor backend.\n-   **Feedback Visual:** A aplicação usa *Toasts* para notificar os usuários sobre erros de API, melhorando a experiência de uso.\n\n## 🛠️ Tecnologias Utilizadas\n\n-   **Frontend:**\n  -   **Angular 20:** Framework principal para a estrutura da aplicação.\n  -   **Ionic 8:** Biblioteca de componentes de UI para criar aplicações híbridas de alta qualidade.\n  -   **TypeScript:** Superset do JavaScript que adiciona tipagem estática.\n  -   **TailwindCSS:** Framework CSS utility-first para estilização rápida e responsiva.\n  -   **RxJS:** Biblioteca para programação reativa, usada para gerenciar chamadas de API e eventos.\n-   **Backend (Servidor de WebHook):**\n  -   **Node.js:** Ambiente de execução JavaScript no servidor.\n  -   **Express.js:** Framework minimalista para criar o servidor e a rota do webhook.\n-   **Testes:**\n  -   **Karma:** Test runner para executar os testes unitários.\n  -   **Jasmine:** Framework de testes behavior-driven para escrever os casos de teste.\n\n## 🏛️ Arquitetura e Boas Práticas\n\n-   **Componentização:** A aplicação é dividida em componentes `standalone` (Pages, Header, Footer), promovendo a separação de responsabilidades.\n-   **Injeção de Dependência (DI):** Utilizamos o `inject()` do Angular para fornecer serviços (`PokeApiService`, `FavoritesService`, `PaginationService`) aos componentes. Isso desacopla o código, facilita a manutenção e torna os testes unitários possíveis.\n-   **Princípio DRY (Don't Repeat Yourself):** A lógica de paginação e busca, que era repetida nas páginas Home e Favoritos, foi abstraída para um serviço reutilizável, o `PaginationService`. Isso centraliza a lógica e torna os componentes mais limpos.\n-   **Reatividade com RxJS:** As chamadas de API retornam `Observables`, e a barra de busca utiliza um `Subject` com `debounceTime` para evitar requisições excessivas enquanto o usuário digita.\n-   **Tratamento de Erros:** As falhas de API são capturadas e o `ToastController` do Ionic é usado para exibir mensagens de erro amigáveis ao usuário, garantindo uma experiência mais robusta.\n\n## 🪝 Implementação de WebHook (Diferencial)\n\nUm WebHook foi implementado para demonstrar a comunicação em tempo real do frontend com um backend. Quando uma ação relacionada aos favoritos ocorre, o frontend notifica um servidor.\n\n#### Como Funciona:\n\n1.  **Ação no Frontend:** O usuário adiciona ou remove um Pokémon dos favoritos no `FavoritesService`.\n2.  **Requisição HTTP:** O serviço imediatamente dispara uma requisição `POST` para o endpoint `http://localhost:3000/webhook`. O `payload` da requisição contém o tipo de evento (`pokemon_added`, `pokemon_removed`, etc.) e os dados relevantes.\n    ```typescript\n    // Em favorites.service.ts\n    this.http.post(this.webhookUrl, {\n      event: 'pokemon_added',\n      pokemonId,\n      timestamp: new Date().toISOString()\n    }).subscribe(...);\n    ```\n3.  **Recepção no Backend:** Um servidor simples criado com Node.js e Express está escutando na porta 3000.\n4.  **Processamento:** O servidor recebe o `payload`, exibe as informações no console e retorna uma resposta de sucesso (`200 OK`). Isso simula o processamento do evento, que em um cenário real poderia disparar um email, atualizar um banco de dados, etc.\n    ```javascript\n    // Em webhook-server/server.js\n    app.post('/webhook', (req, res) =\u003e {\n      console.log('Webhook received:', req.body);\n      res.status(200).json({ message: 'Webhook processed successfully' });\n    });\n    ```\n\n## 🧪 Testes Unitários (Diferencial)\n\nA aplicação possui uma suíte de testes unitários para garantir a qualidade e o funcionamento correto dos componentes.\n\n#### Como os Testes Foram Estruturados:\n\n-   **Ambiente de Teste (`TestBed`):** Para cada componente, o `TestBed` do Angular é usado para configurar um ambiente de teste isolado, declarando o componente a ser testado e fornecendo *mocks* para suas dependências.\n-   **Mocks e Spies:** Dependências como `PokeApiService` e `Router` são substituídas por objetos falsos (`SpyObj`) criados com `jasmine.createSpyObj`. Isso nos permite isolar o componente e controlar o comportamento de suas dependências durante os testes.\n-   **Casos de Teste (`it` blocks):** Cada `it` descreve um comportamento esperado. Nós verificamos se:\n  -   O componente é criado com sucesso.\n  -   A navegação para outras páginas é chamada com os parâmetros corretos.\n  -   A lógica de negócio (como adicionar/remover um favorito) chama os métodos corretos do serviço.\n  -   O estado do componente é atualizado corretamente após uma ação.\n\n```typescript\n// Exemplo de teste em favorites.page.spec.ts\nit('should remove favorite and update pagination', fakeAsync(() =\u003e {\n  // Configuração inicial do estado do componente\n  component.allFavorites = [\n    { id: 1, name: 'bulbasaur' },\n    { id: 25, name: 'pikachu' }\n  ];\n  component.paginationService.total = 2;\n  spyOn(favoritesService, 'removeFavorite'); // Espiona o método\n\n  // Executa a ação\n  component.removeFavorite(1);\n  tick(); // Avança o tempo para resolver operações assíncronas\n\n  // Verificações (Assertions)\n  expect(favoritesService.removeFavorite).toHaveBeenCalledWith(1);\n  expect(component.allFavorites.length).toBe(1);\n  expect(component.paginationService.total).toBe(1);\n}));\n```\n\n## 🚀 Como Executar o Projeto\n\nVocê precisará ter o [Node.js](https://nodejs.org/) e o [pnpm](https://pnpm.io/) (ou npm/yarn) instalados.\n\n#### 1. Frontend (Aplicação Angular/Ionic)\n\n```bash\n# Clone o repositório\ngit clone https://github.com/Vidigal-code/challenge-PokeAPI-Angular.git\n\n# Navegue para a pasta do projeto\ncd challenge-PokeAPI-Angular\n\n# Instale as dependências\npnpm install\n\n# Inicie o servidor de desenvolvimento\npnpm start\n```\n\nA aplicação estará disponível em `http://localhost:4200`.\n\n#### 2. Backend (Servidor de WebHook)\n\nO servidor de webhook deve ser executado simultaneamente em um terminal separado.\n\n```bash\n# Em um novo terminal, navegue para a pasta do servidor\ncd webhook-server\n\n# Instale as dependências\npnpm install\n\n# Crie o arquivo de ambiente (se não existir)\ncp .env.example .env\n\n# Inicie o servidor\npnpm start\n```\n\nO servidor estará escutando em `http://localhost:3000`. Agora, as ações de favoritar na aplicação serão logadas no console deste terminal.\n\n## 📁 Estrutura de Arquivos\n\nA estrutura do projeto foi organizada para manter uma clara separação de responsabilidades.\n\n```\n.\n├── src/\n│   ├── app/\n│   │   ├── favorites/        # Página de Favoritos (componente, HTML, spec)\n│   │   ├── home/             # Página Principal (componente, HTML, spec)\n│   │   ├── pokemon-details/  # Página de Detalhes (componente, HTML, spec)\n│   │   ├── services/         # Serviços reutilizáveis\n│   │   │   ├── favorites.service.ts\n│   │   │   ├── pagination.service.ts\n│   │   │   └── poke-api.service.ts\n│   │   ├── header/           # Componente Header\n│   │   ├── footer/           # Componente Footer\n│   │   ├── app.component.ts  # Componente raiz\n│   │   └── app.routes.ts     # Definição de rotas\n│   ├── assets/               # Ícones e imagens estáticas\n│   └── environments/         # Variáveis de ambiente\n├── webhook-server/           # Servidor Node.js para o WebHook\n│   ├── server.js\n│   ├── package.json\n│   └── .env\n└── ...\n```\n\n## ☁️ Deploy\n\nA aplicação está configurada para deploy no GitHub Pages. Os seguintes scripts no `package.json` automatizam o processo:\n\n-   `build:gh-pages`: Compila o projeto com a URL base correta para o GitHub Pages.\n-   `deploy:gh-pages`: Publica o conteúdo da pasta `dist/` na branch `gh-pages`.\n\n## 👨‍💻 Autor\n\nFeito com ❤️ por **Kauan Vidigal**.\n\n[![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge\u0026logo=github\u0026logoColor=white)](https://github.com/Vidigal-code)\n[![LinkedIn](https://img.shields.io/badge/linkedin-%230077B5.svg?style=for-the-badge\u0026logo=linkedin\u0026logoColor=white)](https://www.linkedin.com/in/kauan-vidigal/)\n\n\u003c/details\u003e\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eEnglish 🇬🇧 (Click to expand)\u003c/strong\u003e\u003c/summary\u003e\n\n## 📜 Table of Contents\n\n- [About The Project](#-about-the-project-1)\n- [✨ Features](#-features)\n- [🛠️ Technologies Used](#️-technologies-used-1)\n- [🏛️ Architecture \u0026 Best Practices](#️-architecture--best-practices)\n- [🪝 WebHook Implementation (Bonus)](#-webhook-implementation-bonus)\n- [🧪 Unit Testing (Bonus)](#-unit-testing-bonus)\n- [🚀 Getting Started](#-getting-started)\n- [📁 File Structure](#-file-structure)\n- [☁️ Deployment](#️-deployment)\n- [👨‍💻 Author](#-author-1)\n\n## 📖 About The Project\n\nThis project is a modern and responsive Pokédex developed as a hybrid application (web/mobile) using the power of **Ionic** and **Angular**. It consumes the [PokeAPI](https://pokeapi.co/) to provide a paginated and searchable list of Pokémon, with a feature-rich detail screen for each creature.\n\nThe project was built following software development best practices, with a focus on clean code, componentization, logic reuse, and a scalable architecture.\n\n## ✨ Features\n\n-   **List \u0026 Pagination:** Browse a complete list of Pokémon with an efficient pagination system.\n-   **Dynamic Search:** Quickly find Pokémon by name or number, with `debounce` to optimize performance.\n-   **Complete Detail Screen:** View detailed information such as types, abilities, stats, habitat, and multiple sprites.\n-   **Favorites System:** Bookmark your favorite Pokémon! The list is saved locally (`localStorage`) to persist between sessions.\n-   **Dedicated Favorites Page:** Manage your collection of favorites on a separate screen, complete with its own search and pagination.\n-   **Responsive Design:** The interface adapts perfectly to any device, whether it's a mobile phone (portrait/landscape) or a desktop, thanks to TailwindCSS.\n-   **WebHook Notifications:** Actions on the favorites list (add, remove, clear) send real-time notifications to a backend server.\n-   **Visual Feedback:** The application uses *Toasts* to notify users of API errors, improving the user experience.\n\n## 🛠️ Technologies Used\n\n-   **Frontend:**\n  -   **Angular 20:** The main framework for the application's structure.\n  -   **Ionic 8:** UI component library for building high-quality hybrid applications.\n  -   **TypeScript:** A superset of JavaScript that adds static typing.\n  -   **TailwindCSS:** A utility-first CSS framework for rapid and responsive styling.\n  -   **RxJS:** A library for reactive programming, used to manage API calls and events.\n-   **Backend (WebHook Server):**\n  -   **Node.js:** JavaScript runtime environment on the server.\n  -   **Express.js:** A minimalist framework for creating the server and the webhook route.\n-   **Testing:**\n  -   **Karma:** A test runner for executing unit tests.\n  -   **Jasmine:** A behavior-driven testing framework for writing test cases.\n\n## 🏛️ Architecture \u0026 Best Practices\n\n-   **Component-Based Architecture:** The application is divided into `standalone` components (Pages, Header, Footer), promoting a separation of concerns.\n-   **Dependency Injection (DI):** We use Angular's `inject()` to provide services (`PokeApiService`, `FavoritesService`, `PaginationService`) to the components. This decouples the code, facilitates maintenance, and makes unit testing possible.\n-   **DRY Principle (Don't Repeat Yourself):** The pagination and search logic, which was duplicated across the Home and Favorites pages, has been abstracted into a reusable service, `PaginationService`. This centralizes the logic and makes the components cleaner.\n-   **Reactivity with RxJS:** API calls return `Observables`, and the search bar uses a `Subject` with `debounceTime` to prevent excessive requests while the user is typing.\n-   **Error Handling:** API failures are caught, and Ionic's `ToastController` is used to display user-friendly error messages, ensuring a more robust experience.\n\n## 🪝 WebHook Implementation (Bonus)\n\nA WebHook was implemented to demonstrate real-time communication from the frontend to a backend. When an action related to favorites occurs, the frontend notifies a server.\n\n#### How It Works:\n\n1.  **Action on the Frontend:** The user adds or removes a Pokémon from favorites in the `FavoritesService`.\n2.  **HTTP Request:** The service immediately fires a `POST` request to the `http://localhost:3000/webhook` endpoint. The request `payload` contains the event type (`pokemon_added`, `pokemon_removed`, etc.) and relevant data.\n    ```typescript\n    // In favorites.service.ts\n    this.http.post(this.webhookUrl, {\n      event: 'pokemon_added',\n      pokemonId,\n      timestamp: new Date().toISOString()\n    }).subscribe(...);\n    ```\n3.  **Reception on the Backend:** A simple server created with Node.js and Express is listening on port 3000.\n4.  **Processing:** The server receives the `payload`, logs the information to the console, and returns a success response (`200 OK`). This simulates event processing, which in a real-world scenario could trigger an email, update a database, etc.\n    ```javascript\n    // In webhook-server/server.js\n    app.post('/webhook', (req, res) =\u003e {\n      console.log('Webhook received:', req.body);\n      res.status(200).json({ message: 'Webhook processed successfully' });\n    });\n    ```\n\n## 🧪 Unit Testing (Bonus)\n\nThe application has a suite of unit tests to ensure the quality and correct functioning of the components.\n\n#### How the Tests Were Structured:\n\n-   **Test Environment (`TestBed`):** For each component, Angular's `TestBed` is used to configure an isolated test environment, declaring the component under test and providing *mocks* for its dependencies.\n-   **Mocks and Spies:** Dependencies like `PokeApiService` and `Router` are replaced with mock objects (`SpyObj`) created with `jasmine.createSpyObj`. This allows us to isolate the component and control the behavior of its dependencies during tests.\n-   **Test Cases (`it` blocks):** Each `it` describes an expected behavior. We check if:\n  -   The component is created successfully.\n  -   Navigation to other pages is called with the correct parameters.\n  -   Business logic (like adding/removing a favorite) calls the correct service methods.\n  -   The component's state is updated correctly after an action.\n\n```typescript\n// Example test in favorites.page.spec.ts\nit('should remove favorite and update pagination', fakeAsync(() =\u003e {\n  // Initial setup of the component's state\n  component.allFavorites = [\n    { id: 1, name: 'bulbasaur' },\n    { id: 25, name: 'pikachu' }\n  ];\n  component.paginationService.total = 2;\n  spyOn(favoritesService, 'removeFavorite'); // Spy on the method\n\n  // Execute the action\n  component.removeFavorite(1);\n  tick(); // Advance time to resolve async operations\n\n  // Assertions\n  expect(favoritesService.removeFavorite).toHaveBeenCalledWith(1);\n  expect(component.allFavorites.length).toBe(1);\n  expect(component.paginationService.total).toBe(1);\n}));\n```\n\n## 🚀 Getting Started\n\nYou will need [Node.js](https://nodejs.org/) and [pnpm](https://pnpm.io/) (or npm/yarn) installed.\n\n#### 1. Frontend (Angular/Ionic App)\n\n```bash\n# Clone the repository\ngit clone https://github.com/Vidigal-code/challenge-PokeAPI-Angular.git\n\n# Navigate to the project folder\ncd challenge-PokeAPI-Angular\n\n# Install dependencies\npnpm install\n\n# Start the development server\npnpm start\n```\n\nThe application will be available at `http://localhost:4200`.\n\n#### 2. Backend (WebHook Server)\n\nThe webhook server must be run simultaneously in a separate terminal.\n\n```bash\n# In a new terminal, navigate to the server folder\ncd webhook-server\n\n# Install dependencies\npnpm install\n\n# Create the environment file (if it doesn't exist)\ncp .env.example .env\n\n# Start the server\npnpm start\n```\n\nThe server will be listening at `http://localhost:3000`. Now, favoriting actions in the application will be logged in this terminal's console.\n\n## 📁 File Structure\n\nThe project structure was organized to maintain a clear separation of concerns.\n\n```\n.\n├── src/\n│   ├── app/\n│   │   ├── favorites/        # Favorites Page (component, HTML, spec)\n│   │   ├── home/             # Home Page (component, HTML, spec)\n│   │   ├── pokemon-details/  # Details Page (component, HTML, spec)\n│   │   ├── services/         # Reusable services\n│   │   │   ├── favorites.service.ts\n│   │   │   ├── pagination.service.ts\n│   │   │   └── poke-api.service.ts\n│   │   ├── header/           # Header component\n│   │   ├── footer/           # Footer component\n│   │   ├── app.component.ts  # Root component\n│   │   └── app.routes.ts     # Route definitions\n│   ├── assets/               # Static assets (icons, images)\n│   └── environments/         # Environment variables\n├── webhook-server/           # Node.js server for the WebHook\n│   ├── server.js\n│   ├── package.json\n│   └── .env\n└── ...\n```\n\n## ☁️ Deployment\n\nThe application is configured for deployment to GitHub Pages. The following scripts in `package.json` automate the process:\n\n-   `build:gh-pages`: Compiles the project with the correct base URL for GitHub Pages.\n-   `deploy:gh-pages`: Publishes the contents of the `dist/` folder to the `gh-pages` branch.\n\n## 👨‍💻 Author\n\nMade with ❤️ by **Kauan Vidigal**.\n\n[![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge\u0026logo=github\u0026logoColor=white)](https://github.com/Vidigal-code)\n[![LinkedIn](https://img.shields.io/badge/linkedin-%230077B5.svg?style=for-the-badge\u0026logo=linkedin\u0026logoColor=white)](https://www.linkedin.com/in/kauan-vidigal/)\n\n\u003c/details\u003e\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvidigal-code%2Fchallenge-pokeapi-angular","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvidigal-code%2Fchallenge-pokeapi-angular","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvidigal-code%2Fchallenge-pokeapi-angular/lists"}