Skip to content

Commit

Permalink
Fix the code
Browse files Browse the repository at this point in the history
  • Loading branch information
rr-tri committed Nov 28, 2023
1 parent 34d69dc commit 57e3373
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 218 deletions.
64 changes: 40 additions & 24 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import React from 'react'
import { BrowserRouter as Router, Switch, Route } 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 Router, Switch, Route } 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 { data: pokemonList, error, isLoading } = useApi('https://pokeapi.co/api/v2/pokemon/?limit=50', mapResults)
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} />;
}

return (
Expand All @@ -27,15 +32,26 @@ const App = () => {
<Route exact path="/">
<PokemonList pokemonList={pokemonList} />
</Route>
<Route path="/pokemon/:name" render={(routeParams) => {
const pokemonId = pokemonList.find(({ name }) => name === routeParams.match.params.name).id
const previous = pokemonList.find(({ id }) => id === pokemonId - 1)
const next = pokemonList.find(({ id }) => id === pokemonId + 1)
return <PokemonPage pokemonList={pokemonList} previous={previous} next={next} />
}} />
<Route
path="/pokemon/:name"
render={(routeParams) => {
const pokemonId = pokemonList.find(
({ name }) => name === routeParams.match.params.name
).id;
const previous = pokemonList.find(({ id }) => id === pokemonId - 1);
const next = pokemonList.find(({ id }) => id === pokemonId + 1);
return (
<PokemonPage
pokemonList={pokemonList}
previous={previous}
next={next}
/>
);
}}
/>
</Switch>
</Router>
)
}
);
};

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("-", " ");

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)
// 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;
10 changes: 5 additions & 5 deletions src/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import './styles.css'
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./styles.css";

ReactDOM.render(<App />, document.getElementById('app'))
ReactDOM.render(<App />, document.getElementById("app"));
24 changes: 12 additions & 12 deletions src/useApi.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { useEffect, useState } from 'react'
import axios from 'axios'
import { useEffect, useState } from "react";
import axios from "axios";

const useApi = (url, mapResults = (result) => result) => {
const [data, setData] = useState()
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState()
const [data, setData] = useState();
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState();
useEffect(() => {
setIsLoading(true)
setIsLoading(true);
axios
.get(url)
.then(response => setData(mapResults(response.data)))
.then((response) => setData(mapResults(response.data)))
.catch(setError)
.finally(() => setIsLoading(false))
}, [url])
.finally(() => setIsLoading(false));
}, [url]);

return { data, isLoading, error }
}
return { data, isLoading, error };
};

export { useApi }
export { useApi };
74 changes: 40 additions & 34 deletions test/App.jest.spec.jsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,47 @@
import React from 'react'
import { render, screen } from '@testing-library/react'
import axiosMock from 'axios'
import { act } from 'react-dom/test-utils'
import '@testing-library/jest-dom/extend-expect'
import App from '../src/App'
import React from "react";
import { render, screen } from "@testing-library/react";
import axiosMock from "axios";
import { act } from "react-dom/test-utils";
import "@testing-library/jest-dom/extend-expect";
import App from "../src/App";

jest.mock('axios')
jest.mock("axios");

describe('<App />', () => {
it('fetches data', async () => {
axiosMock.get.mockResolvedValueOnce(
{
data: {
results: [{ url: 'https://pokeapi.co/api/v2/pokemon/1/', name: 'bulbasaur', id: 1 }]
}
}
)
describe("<App />", () => {
it("fetches data", async () => {
axiosMock.get.mockResolvedValueOnce({
data: {
results: [
{
url: "https://pokeapi.co/api/v2/pokemon/1/",
name: "bulbasaur",
id: 1,
},
],
},
});
await act(async () => {
render(<App />)
})
expect(axiosMock.get).toHaveBeenCalledTimes(1)
expect(axiosMock.get).toHaveBeenCalledWith('https://pokeapi.co/api/v2/pokemon/?limit=50')
})
render(<App />);
});
expect(axiosMock.get).toHaveBeenCalledTimes(1);
expect(axiosMock.get).toHaveBeenCalledWith(
"https://pokeapi.co/api/v2/pokemon/?limit=50"
);
});

it('shows LoadingSpinner', async () => {
axiosMock.get.mockResolvedValueOnce({})
it("shows LoadingSpinner", async () => {
axiosMock.get.mockResolvedValueOnce({});
await act(async () => {
const { getByAltText } = render(<App />)
expect(getByAltText('Loading...')).toBeVisible()
})
})
const { getByAltText } = render(<App />);
expect(getByAltText("Loading...")).toBeVisible();
});
});

it('shows error', async () => {
axiosMock.get.mockRejectedValueOnce(new Error())
it("shows error", async () => {
axiosMock.get.mockRejectedValueOnce(new Error());
await act(async () => {
render(<App />)
})
expect(screen.getByTestId('error')).toBeVisible()
})
})
render(<App />);
});
expect(screen.getByTestId("error")).toBeVisible();
});
});
Loading

0 comments on commit 57e3373

Please sign in to comment.