16 | {pokemons.map((pokemon) => (
17 |
history.push(`/${pokemon.number}`)}
20 | >
21 |
22 | #{pokemon.number} {pokemon.name}
23 |
24 |
25 | ))}
26 |
27 | );
28 | };
29 |
30 | export default Home;
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Clean architecture + TDD on front end project
2 |
3 | I've tried **TDD** with **Clean architecture** implementation in frontend side. It can run either with **InMemory** data or with data from **PokeApi** (rest API). It works with **React** but strength of this concept is to easily change framework and sources (database, ...). So if you fork it, you can add **VueJS** or **AngularJS** without any issues and without touching of core logic.
4 |
5 | **All core logic is completely independent from data source and framework.**
6 |
7 | I'll do more complex projects with this concept because it's kinda a prerequisite for my actual and future works as freelancer. If you are interested as I am, please contact me or follow me on Github to check next updates.
8 |
9 | It runs with **RxJS** for observable capabilities (next time, I will focus on **Redux** and **Redux-Thunk**).
10 |
11 | ## Installation
12 |
13 | ```
14 | yarn
15 | ```
16 |
17 | ## Start project
18 |
19 | You can start it with two differents sources :
20 |
21 | **InMemory**
22 | ```
23 | yarn start
24 | ```
25 |
26 | **Rest API**
27 | ```
28 | yarn start:rest
29 | ```
30 |
--------------------------------------------------------------------------------
/src/core/adapters/secondaries/real/mappers/pokemon.mappers.ts:
--------------------------------------------------------------------------------
1 | import {
2 | PokemonDTO,
3 | PokemonPageDTO,
4 | PokemonSimpleDTO,
5 | } from "../DTO/PokemonDTO";
6 | import { PokemonBuilder } from "core/usecases/pokemon.builder";
7 | import { Pokemon } from "core/domain/entities/pokemon";
8 |
9 | export class PokemonMappers {
10 | static mapToPokemon(pokemonDTO: PokemonDTO): Pokemon {
11 | return new PokemonBuilder()
12 | .withNumber(pokemonDTO.id.toString())
13 | .withName(pokemonDTO.name)
14 | .withDescription(pokemonDTO.types.map((t) => t.type.name).join(", "))
15 | .withHeight(pokemonDTO.height.valueOf())
16 | .withWeight(pokemonDTO.weight.valueOf())
17 | .withAvatar(pokemonDTO.sprites.front_default)
18 | .build();
19 | }
20 |
21 | static mapPageToPokemons(pokemonPageDTO: PokemonPageDTO): Pokemon[] {
22 | return pokemonPageDTO.results.map(
23 | (pokemonDTO: PokemonSimpleDTO, index: number) => {
24 | return new PokemonBuilder()
25 | .withName(pokemonDTO.name)
26 | .withNumber((index + 1).toString())
27 | .build();
28 | }
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/views/PokemonDetails.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { useHistory, useParams } from "react-router-dom";
3 | import { pokemonHandler } from "core/adapters/primaries/pokemon.module";
4 | import { Pokemon } from "core/domain/entities/pokemon";
5 |
6 | const PokemonDetails = () => {
7 | const [pokemon, setPokemon] = useState