Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
webpack.config.js
node_modules/
dist/
.eslintrc.js
app.js
65 changes: 22 additions & 43 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,28 @@
module.exports = {
"env": {
"browser": true,
"es6": true,
"jest/globals": true
env: {
browser: true,
es6: true,
"jest/globals": true,
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
extends: ["eslint:recommended", "plugin:react/recommended"],
parserOptions: {
ecmaFeatures: {
jsx: true,
},
"ecmaVersion": 2018,
"sourceType": "module"
ecmaVersion: 2018,
sourceType: "module",
},
"plugins": [
"react", "jest"
],
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"never"
],
"eqeqeq": "error",
plugins: ["react", "jest"],
rules: {
indent: ["error", 2],
"linebreak-style": ["error", "unix"],
quotes: ["error", "double"],
semi: ["error", "always"],
eqeqeq: "error",
"no-trailing-spaces": "error",
"object-curly-spacing": [
"error", "always"
],
"arrow-spacing": [
"error", { "before": true, "after": true }
],
"object-curly-spacing": ["error", "always"],
"arrow-spacing": ["error", { before: true, after: true }],
"no-console": "error",
"react/prop-types": 0
}
}
"react/prop-types": 0,
},
};
20 changes: 20 additions & 0 deletions .github/workflows/hello.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Hello World!

on:
push:
branches:
- main

jobs:
hello_world_job:
runs-on: ubuntu-latest
steps:
- name: Say hello
run: |
echo "Hello World!"
- name: Now it is
run: |
date
- name: Directory content
run: |
ls
27 changes: 27 additions & 0 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Deployment pipeline

on:
push:
branches:
- main
pull_request:
branches: [main]
types: [opened, synchronized]

jobs:
simple_deployment_pipeline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: "20"
- name: Install dependencies
run: npm install
- name: Check style
run: npm run eslint
- name: build
run: npm run build
- name: test
run: npm run test
- uses: actions/checkout@v2
75 changes: 47 additions & 28 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,64 @@
import React from 'react'
import { BrowserRouter as Router, Routes, Route, useMatch } from 'react-router-dom'
import { useApi } from './useApi'
import LoadingSpinner from './LoadingSpinner'
import ErrorMessage from './ErrorMessage'
import PokemonPage from './PokemonPage'
import PokemonList from './PokemonList'
import React from "react";
import { BrowserRouter as Routes, Route, useMatch } from "react-router-dom";
import { useApi } from "./useApi";
import LoadingSpinner from "./LoadingSpinner";
import ErrorMessage from "./ErrorMessage";
import PokemonPage from "./PokemonPage";
import PokemonList from "./PokemonList";

const mapResults = (({ results }) => results.map(({ url, name }) => ({
url,
name,
id: parseInt(url.match(/\/(\d+)\//)[1])
})))
const mapResults = ({ results }) =>
results.map(({ url, name }) => ({
url,
name,
id: parseInt(url.match(/\/(\d+)\//)[1]),
}));

const App = () => {
const match = useMatch('/pokemon/:name')
const { data: pokemonList, error, isLoading } = useApi('https://pokeapi.co/api/v2/pokemon/?limit=50', mapResults)
const match = useMatch("/pokemon/:name");
const {
data: pokemonList,
error,
isLoading,
} = useApi("https://pokeapi.co/api/v2/pokemon/?limit=50", mapResults);

if (isLoading) {
return <LoadingSpinner />
return <LoadingSpinner />;
}
if (error) {
return <ErrorMessage error={error} />
return <ErrorMessage error={error} />;
}

let next = null
let previous = null
let next = null;
let previous = null;

if (match && match.params) {
const pokemonId = pokemonList.find(({ name }) => name === match.params.name).id
previous = pokemonList.find(({ id }) => id === pokemonId - 1)
next = pokemonList.find(({ id }) => id === pokemonId + 1)
const pokemonId = pokemonList.find(
({ name }) => name === match.params.name
).id;
previous = pokemonList.find(({ id }) => id === pokemonId - 1);
next = pokemonList.find(({ id }) => id === pokemonId + 1);
}

return (
<Routes>
<Route exact path="/" element={<PokemonList pokemonList={pokemonList} />} />
<Route exact path="/pokemon/:name" element={
<PokemonPage pokemonList={pokemonList} previous={previous} next={next} />
} />
<Route
exact
path="/"
element={<PokemonList pokemonList={pokemonList} />}
/>
<Route
exact
path="/pokemon/:name"
element={
<PokemonPage
pokemonList={pokemonList}
previous={previous}
next={next}
/>
}
/>
</Routes>
)
}
);
};

export default App
export default App;
6 changes: 3 additions & 3 deletions src/ErrorMessage.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import React from "react";

const ErrorMessage = ({ error }) => (
<div data-testid="error">An error occured: {error.toString()}</div>
)
);

export default ErrorMessage
export default ErrorMessage;
12 changes: 8 additions & 4 deletions src/LoadingSpinner.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React from 'react'
import React from "react";

const LoadingSpinner = () => (
<img className="loading-spinner" alt="Loading..." src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/poke-ball.png" />
)
<img
className="loading-spinner"
alt="Loading..."
src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/poke-ball.png"
/>
);

export default LoadingSpinner
export default LoadingSpinner;
10 changes: 4 additions & 6 deletions src/PokemonAbility.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React from 'react'
import React from "react";

const PokemonAbility = ({ abilityName }) => (
<div className="pokemon-ability">
<div className="pokemon-ability-type">Hidden ability</div>
<div className="pokemon-ability-name">
{abilityName}
</div>
<div className="pokemon-ability-name">{abilityName}</div>
</div>
)
);

export default PokemonAbility
export default PokemonAbility;
25 changes: 14 additions & 11 deletions src/PokemonList.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import React from 'react'
import { Link } from 'react-router-dom'
import React from "react";
import { Link } from "react-router-dom";

const PokemonList = ({ pokemonList }) => {
return (
<div className="list-container">
{pokemonList.map(({ id, name }) => (
<Link key={id} to={`/pokemon/${name}`} className="list-item" style={{ backgroundImage: `url(${`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`})` }}>
<div
className="list-item-name"
>
{name}
</div>
<Link
key={id}
to={`/pokemon/${name}`}
className="list-item"
style={{
backgroundImage: `url(${`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`})`,
}}
>
<div className="list-item-name">{name}</div>
</Link>
))}
</div>
)
}
);
};

export default PokemonList
export default PokemonList;
69 changes: 44 additions & 25 deletions src/PokemonPage.jsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,40 @@
import React from 'react'
import { Link, useParams } from 'react-router-dom'
import LoadingSpinner from './LoadingSpinner'
import { useApi } from './useApi'
import PokemonAbility from './PokemonAbility'
import ErrorMessage from './ErrorMessage'
import React from "react";
import { Link, useParams } from "react-router-dom";
import LoadingSpinner from "./LoadingSpinner";
import { useApi } from "./useApi";
import PokemonAbility from "./PokemonAbility";
import ErrorMessage from "./ErrorMessage";

const formatName = (nameWithDash) => nameWithDash.replace('-', ' ')
const formatName = (nameWithDash) => nameWithDash.replace("-", " ");

// the is the component for Pokemon Page
const PokemonPage = ({ previous, next }) => {
const { name } = useParams()
const { data: pokemon, error, isLoading } = useApi(`https://pokeapi.co/api/v2/pokemon/${name}`)
const { name } = useParams();
const {
data: pokemon,
error,
isLoading,
} = useApi(`https://pokeapi.co/api/v2/pokemon/${name}`);

if (isLoading) {
return <LoadingSpinner />
return <LoadingSpinner />;
}
if (error) {
return <ErrorMessage error={error} />
return <ErrorMessage error={error} />;
}

const { type } = pokemon.types.find((type) => type.slot === 1)
const stats = pokemon.stats.map((stat) => ({
name: formatName(stat.stat.name),
value: stat.base_stat
})).reverse()
const normalAbility = pokemon.abilities.find((ability) => !ability.is_hidden)
const hiddenAbility = pokemon.abilities.find((ability) => ability.is_hidden === true)
const { type } = pokemon.types.find((type) => type.slot === 1);
const stats = pokemon.stats
.map((stat) => ({
name: formatName(stat.stat.name),
value: stat.base_stat,
}))
.reverse();
const normalAbility = pokemon.abilities.find((ability) => !ability.is_hidden);
const hiddenAbility = pokemon.abilities.find(
(ability) => ability.is_hidden === true
);

console.log('hiddenAbility=', hiddenAbility)
return (
<>
<div className="links">
Expand All @@ -35,7 +43,10 @@ const PokemonPage = ({ previous, next }) => {
{next && <Link to={`/pokemon/${previous.name}`}>Next</Link>}
</div>
<div className={`pokemon-page pokemon-type-${type.name}`}>
<div className="pokemon-image" style={{ backgroundImage: `url(${pokemon.sprites.front_default})` }} />
<div
className="pokemon-image"
style={{ backgroundImage: `url(${pokemon.sprites.front_default})` }}
/>
<div className="pokemon-info">
<div className="pokemon-name">{pokemon.name}</div>
<div className="pokemon-stats" data-testid="stats">
Expand All @@ -51,13 +62,21 @@ const PokemonPage = ({ previous, next }) => {
</table>
</div>
<div className="pokemon-abilities">
{normalAbility && <PokemonAbility abilityName={formatName(normalAbility.ability.name)} />}
{hiddenAbility && <PokemonAbility abilityName={formatName(hiddenAbility.ability.name)} />}
{normalAbility && (
<PokemonAbility
abilityName={formatName(normalAbility.ability.name)}
/>
)}
{hiddenAbility && (
<PokemonAbility
abilityName={formatName(hiddenAbility.ability.name)}
/>
)}
</div>
</div>
</div>
</>
)
}
);
};

export default PokemonPage
export default PokemonPage;
Loading