diff --git a/src/Home.js b/src/Home.js index afa7452a0..8a97f772e 100644 --- a/src/Home.js +++ b/src/Home.js @@ -1,4 +1,4 @@ -import "./App.css"; +import "../../App.css"; import { useState, useEffect } from "react"; import { NavLink } from "react-router-dom"; @@ -6,27 +6,44 @@ function Home() { const [text, setText] = useState(""); const [isReady, setIsReady] = useState(false); + const InputHandler = (event) => { + setText(event.target.value); + if (event.target.value === "Ready!") { + setIsReady(true); + } + if (event.target.value !== "Ready!"){ + setIsReady(false) + } + }; + return (
- + + + Requirement: Try to show the hidden image and make it clickable that goes to /pokedex when the input below is "Ready!" remember to hide the red text away when "Ready!" is in the textbox.

Are you ready to be a pokemon master?

- - I am not ready yet! + + {isReady ? ( + "" + ) : ( + I am not ready yet! + )}
); } export default Home; + diff --git a/src/PokeDex.js b/src/PokeDex.js index c7b071b04..4487f992d 100644 --- a/src/PokeDex.js +++ b/src/PokeDex.js @@ -1,13 +1,64 @@ -import "./App.css"; -import { useState, useEffect } from "react"; -import ReactLoading from "react-loading"; -import axios from "axios"; -import Modal from "react-modal"; +import './App.css'; +import { useState, useEffect } from 'react'; +import ReactLoading from 'react-loading'; +import axios from 'axios'; +import Modal from 'react-modal'; + +import DetailCard from './components/DetailCard'; +import ThumbnailCard from './components/ThumbnailCard'; +import { MdNavigateNext, MdNavigateBefore } from 'react-icons/md'; function PokeDex() { - const [pokemons, setPokemons] = useState([]); - const [pokemonDetail, setPokemonDetail] = useState(null); - const [isLoading, setIsLoading] = useState(false); + const [pokemons, setPokemons] = useState([]); + const [currentPokemonList, setCurrentPokemonList] = useState([]); + const [pokemonDetail, setPokemonDetail] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [nextLink, setNextLink] = useState(''); + const [prevLink, setPrevLink] = useState(''); + const [search, setSearch] = useState(''); + const [notfound, setNotfound] = useState(false); + const [pokemonApi, setPokemonApi] = useState('https://pokeapi.co/api/v2/pokemon'); + + useEffect(() => { + axios.get(pokemonApi).then((response) => { + console.log(response); + setPokemons(response.data.results); + setCurrentPokemonList(response.data.results); + setNextLink(response.data.next); + setPrevLink(response.data.previous); + }); + setIsLoading(false); + }, [pokemonApi]); + + useEffect(() => { + if (search === '') { + setPokemons(currentPokemonList); + setNotfound(false); + } else { + const searchedPokemon = currentPokemonList.filter((value) => { + return value.name.toLowerCase().includes(search.toLowerCase()); + }); + if (searchedPokemon.length > 0) { + setNotfound(false); + setPokemons(searchedPokemon); + } else { + setNotfound(true); + } + } + }, [search, currentPokemonList]); + + const handleChange = (e) => setSearch(e.target.value); + + const onClickPokemon = (url) => { + axios.get(url).then((response) => { + console.log(response.data); + setPokemonDetail(response.data); + }); + }; + + const onClickNext = () => setPokemonApi(nextLink); + + const onClickPrev = () => setPokemonApi(prevLink); const customStyles = { content: { @@ -31,10 +82,13 @@ function PokeDex() {

Requirement:

@@ -56,15 +113,43 @@ function PokeDex() { <>
- Implement loader here +
) : ( <> -

Welcome to pokedex !

- Implement Pokedex list here - +

Welcome to pokedex !

+
+ + + +
+ {notfound &&

Couldn't find the searched pokemon!

} + {pokemons && ( +
+ {pokemons.map((pokemon, index) => ( + onClickPokemon(pokemon.url)} name={pokemon.name} /> + ))} +
+ )} + )} {pokemonDetail && ( @@ -76,7 +161,8 @@ function PokeDex() { }} style={customStyles} > -
+ + {/*
Requirement:
  • show the sprites front_default as the pokemon image
  • @@ -85,9 +171,12 @@ function PokeDex() { required in tabular format
  • Create a bar chart based on the stats above
  • -
  • Create a buttton to download the information generated in this modal as pdf. (images and chart must be included)
  • +
  • + Create a buttton to download the information generated in this + modal as pdf. (images and chart must be included) +
-
+
*/} )} diff --git a/src/components/DetailCard.css b/src/components/DetailCard.css new file mode 100644 index 000000000..3afe87f24 --- /dev/null +++ b/src/components/DetailCard.css @@ -0,0 +1,84 @@ +.card-container { + width: 80vw; + height: auto; +} + +.pokemon-name { + font-size: xx-large; + font-weight: bold; + line-height: 0%; + text-transform: capitalize; +} + +.top-content { + display: grid; +} + +.pokemon-img { + width: 100%; + max-height: 200px; + object-fit: cover; +} + +table { + width: 100%; + text-align: left; + padding: 5px; + border: 1px aliceblue solid; +} + +td, th { + text-transform: capitalize; +} + +.table-wrapper { + display: flex; + align-items: center; +} + +.barchart-wrapper { + width: 100%; + padding-top: 20px; + margin: 0 auto; +} + +.bar-box { + background-color: #302e2e; + width: 150px; + height: 6px; +} + +.progress-bar { + background-color: yellow; + height: 6px; +} + +button { + padding: 5px; + background-color: yellow; + color: black; + margin-top: 20px; +} + +@media only screen and (min-width: 770px) { + .card-container { + width: 600px; + } + .top-content { + grid-template-columns: 50% 50%; + } + .pokemon-img { + width: 80%; + height: auto; + max-height: none; + object-fit: cover; + } + + .barchart-wrapper { + padding-top: 0; + } + + .bar-box { + width: 200px; + } +} diff --git a/src/components/DetailCard.jsx b/src/components/DetailCard.jsx new file mode 100644 index 000000000..9245cc3fd --- /dev/null +++ b/src/components/DetailCard.jsx @@ -0,0 +1,62 @@ +import React, { useRef } from "react"; +import './DetailCard.css'; +import { useReactToPrint } from "react-to-print"; + +const DetailCard = (props) => { + const printRef = useRef(null); // ref to point when print pdf is triggered + const name = props?.detail?.name; + const image = props?.detail?.sprites?.front_default; + const detailStats = props?.detail?.stats; + + const onDownloadPdf = useReactToPrint({ + content: () => printRef.current + }); + + const renderStatsTable = (stats) => ( +
+ + + + + + {stats.map((stat, index) => ( + + + + + ))} +
NameBase Stats
{stat.stat.name}{stat.base_stat}
+
+ ); + + const renderBarChart = (stats) => ( +
+ + {stats.map((stat, index) => ( + + + + + ))} +
{stat.stat.name} +
+
+
+
+
+ ); + + return ( +
+ {name} +
+ {name} + {renderStatsTable(detailStats)} +
+ {renderBarChart(detailStats)} + +
+ ); +}; + +export default DetailCard; diff --git a/src/components/ThumbnailCard.css b/src/components/ThumbnailCard.css new file mode 100644 index 000000000..146f1b0ae --- /dev/null +++ b/src/components/ThumbnailCard.css @@ -0,0 +1,64 @@ +.item-card { + width: 100px; + height: 135px; + margin-bottom: 20px; + text-align: center; + display: grid; + border: 1px white solid; + border-radius: 10px; + color: aliceblue; + cursor: pointer; +} +.item-card:hover { + background-color: yellow; + color: black; +} + +.img-box { + width: 100px; + height: 100px; + display: flex; + align-items: center; + justify-content: center; +} + +.item-img { + width: 80px; + height: 80px; +} +.item-img:hover { + width: 100px; + height: 100px; +} + +.item-name { + font-size: 16px; + padding-bottom: 8px; + font-weight: bold; + text-transform: capitalize; +} + +@media only screen and (min-width: 770px) { + .item-card { + width: 200px; + height: 250px; + } + + .img-box { + width: 200px; + height: 200px; + } + + .item-img { + width: 150px; + height: 150px; + } + .item-img:hover { + width: 200px; + height: 200px; + } + + .item-name { + font-size: 20px; + } + } \ No newline at end of file diff --git a/src/components/ThumbnailCard.jsx b/src/components/ThumbnailCard.jsx new file mode 100644 index 000000000..6da6b7f53 --- /dev/null +++ b/src/components/ThumbnailCard.jsx @@ -0,0 +1,15 @@ +import React from 'react' +import './ThumbnailCard.css' + +const ThumbnailCard = (props) => { + return ( +
+
+ item thumbnail +
+ {props.name} +
+ ) +} + +export default ThumbnailCard \ No newline at end of file