Skip to content

Commit

Permalink
feat(app): move table & add pokemon card
Browse files Browse the repository at this point in the history
  • Loading branch information
Facundo Ledesma authored and Facundo Ledesma committed Dec 30, 2022
1 parent af7bf7f commit 67f4b05
Show file tree
Hide file tree
Showing 15 changed files with 355 additions and 218 deletions.
10 changes: 5 additions & 5 deletions src/components/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from "react";
import Home from "@components/home/Home";
import Header from "@components/header/Header";
import "./app.scss";
import React from 'react';
import Home from '@components/home/Home';
import Header from '@components/header/Header';
import './app.scss';

const App: React.FC = () => {
const App: React.FC = (): JSX.Element => {
return (
<div className="app">
<Header />
Expand Down
4 changes: 2 additions & 2 deletions src/components/app/app.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#root {
.app {
width: 80%;
margin: 0 auto;
padding: 2rem;
padding: 2rem 0;
text-align: center;
}
92 changes: 35 additions & 57 deletions src/components/card/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,78 +1,56 @@
import React from 'react';
import { useSinglePokemon } from '@components/hooks/useSinglePokemon';
import { Indeterminate } from '@faculedesma/ledesma-lib';
import React, { useState } from 'react';
import { ISinglePokemonParsed } from 'src/types';
import './card.scss';

interface IPokemonCardProps {
pokemonId: string;
interface ICardProps {
pokemon: ISinglePokemonParsed;
}

export const PokemonCard = ({ pokemonId }: IPokemonCardProps): JSX.Element => {
const { data, isLoading, isError } = useSinglePokemon(pokemonId);
export const Card: React.FC<ICardProps> = ({ pokemon }): JSX.Element => {
const [isImageLoaded, setIsImageLoaded] = useState<boolean>(false);

if (isLoading) {
return <div>Loading...</div>;
}
const handleImageLoaded = (): void => setIsImageLoaded(true);

if (isError) {
return <div>Error!</div>;
}

const pokemon = data;

return (
<div className={`card`}>
<div className={`card-header`}>
return pokemon !== undefined ? (
<div className="card">
<div className="card-header">
<div className="image-container">
<img src={pokemon?.imageSrc} alt="header-card" />
<img
src={pokemon?.imageSrc}
alt="poke-default"
onLoad={handleImageLoaded}
/>
{!isImageLoaded && <Indeterminate />}
</div>
</div>
<div className={`card-content`}>
<div>
<div className="card-content">
<div className="top">
<b>{pokemon?.name}</b>
<span style={{ marginLeft: 10, opacity: 0.5 }}>
{pokemon?.stats.hp}Hp
</span>
<span className="hp">{pokemon?.stats.hp}Hp</span>
</div>
<div>
<span style={{ transform: 'translateY(40%)', opacity: 0.5 }}>
{pokemon?.stats.experience}Exp
</span>
<div className="bottom">
<span className="exp">{pokemon?.stats.experience}Exp</span>
</div>
</div>
<div className={`card-footer`}>
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}
>
<b style={{ fontSize: 16 }}>{pokemon?.stats.attack}K</b>
<p style={{ fontSize: 12, opacity: 0.5 }}>Attack</p>
<div className="card-footer">
<div className="stat">
<b>{pokemon?.stats.attack}K</b>
<p>Attack</p>
</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}
>
<b style={{ fontSize: 16 }}>{pokemon?.stats.specialAttack}K</b>
<p style={{ fontSize: 12, opacity: 0.5 }}>Special</p>
<div className="stat">
<b>{pokemon?.stats.specialAttack}K</b>
<p>Special</p>
</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}
>
<b style={{ fontSize: 16 }}>{pokemon?.stats.defense}K</b>
<p style={{ fontSize: 12, opacity: 0.5 }}>Defense</p>
<div className="stat">
<b>{pokemon?.stats.defense}K</b>
<p>Defense</p>
</div>
</div>
</div>
) : (
<>No pokemon selected</>
);
};

export default PokemonCard;
export default Card;
93 changes: 72 additions & 21 deletions src/components/card/card.scss
Original file line number Diff line number Diff line change
@@ -1,43 +1,77 @@
.card {
.card,
.card-loading,
.card-empty {
height: 400px;
width: 300px;
border: 1px solid black;
border-radius: 5px;
background-color: white;
border: 2px solid black;
border-radius: 8px;
background-color: #FFFCF3;
box-shadow: 0px 4px 0px black;

&-empty {
display: flex;
align-items: center;
justify-content: center;
}

&-header {
height: 30%;
background-color: yellow;
background-color: #FFCD69;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid black;
border-bottom: 2px solid black;
border-radius: 8px 8px 0 0;

.image-container {
position: relative;
width: 40%;
height: 100%;
width: 150px;
height: 150px;
border-radius: 50%;
border: 1.5px solid black;
transform: translateY(50%);
border: 2px solid black;
transform: translateY(37%);
background-color: #FFFCF3;

img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
clip-path: circle(50%);
border-radius: 50%;
top: 10%;
left: 10%;
width: 80%;
height: 80%;
}

.indeterminate {
position: absolute;
transform: translate(-50%, 50%);
}
}
}

&-content {
height: 45%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;

.top {
position: absolute;
width: 100%;
top: 50%;

.hp {
margin-left: 10px;
opacity: 0.5;
}
}

.bottom {
position: absolute;
width: 100%;
top: 65%;

.exp {
transform: translateY(40%);
opacity: 0.5;
}
}
}

&-footer {
Expand All @@ -46,6 +80,23 @@
display: flex;
align-items: center;
justify-content: space-around;
border-top: 1px solid black;
border-top: 2px solid black;

.stat {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;

b {
font-size: 16px;
}

p {
font-size: 12px;
opacity: 0.5;
}
}
}
}
2 changes: 1 addition & 1 deletion src/components/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PokemonLogo from '@assets/images/pokemon-logo.png';
import PokemonPikachu from '@assets/images/pokemon-svg.png';
import './header.scss';

const Header = (): JSX.Element => {
const Header: React.FC = (): JSX.Element => {
return (
<div className="header">
<img src={PokemonLogo} alt="poke-logo" />
Expand Down
113 changes: 11 additions & 102 deletions src/components/home/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,110 +1,19 @@
import React, { useState } from 'react';
import {
Button,
Table,
TableRow,
TableHeaderCell,
TableCell
} from '@faculedesma/ledesma-lib';
import PokemonCard from '@components/card/Card';
import { usePokemons } from '@components/hooks/usePokemons';
import { capitalizeFirstLetter } from '@utils/utils';
import HomeTable from './HomeTable';
import HomeCard from './HomeCard';
import './home.scss';

const getPokemonIdFromURL = (url: string): string => {
const parts = url.split('/');
return parts[parts.length - 2];
};

const Home = (): JSX.Element => {
const [offset, setOffset] = useState<number>(0);
const [selectedPokemonId, setSelectedPokemonId] = useState<
string | undefined
>(undefined);

const { data, isLoading, isError } = usePokemons(offset);

if (isLoading) {
return <div>Loading...</div>;
}

if (isError) {
return <div>Error!</div>;
}

const handleSelectRow = (id: string): void => setSelectedPokemonId(id);

const handlePrev = (): void => setOffset(offset - 10);

const handleNext = (): void => setOffset(offset + 10);

if (data !== undefined) {
const columns = Object.keys(data.results[0]).map((column) =>
capitalizeFirstLetter(column)
);
const rows = data.results.map((row: any) => [
capitalizeFirstLetter(row.name),
row.url
]);
const Home: React.FC = (): JSX.Element => {
const [selectedPokemonId, setSelectedPokemonId] = useState<string>('');

return (
<div className="home">
<Table>
<>
<thead>
<TableRow>
<>
{columns?.map((name, columnIndex) => {
return (
<TableHeaderCell key={columnIndex}>
{name}
</TableHeaderCell>
);
})}
</>
</TableRow>
</thead>
<tbody>
{rows?.map((row: any, rowIndex: number) => {
return (
<TableRow
key={rowIndex}
onClick={() => handleSelectRow(getPokemonIdFromURL(row[1]))}
>
<>
{row.map((data: any, rowDataIndex: number) => {
return <TableCell key={rowDataIndex}>{data}</TableCell>;
})}
</>
</TableRow>
);
})}
</tbody>
</>
</Table>
<div>
<Button onClick={handlePrev} disabled={offset === 0}>
Previous
</Button>
<Button
onClick={handleNext}
disabled={offset === Math.trunc(data.count / 10) + 1}
>
Next
</Button>
<span>Page: {offset / 10 + 1}</span>
<span>Pages: {Math.trunc(data.count / 10) + 1}</span>
</div>
{selectedPokemonId != null ? (
<div>
<PokemonCard pokemonId={selectedPokemonId} />
</div>
) : null}
</div>
);
}
const handleSelectPokemonId = (id: string): void => setSelectedPokemonId(id);

return <></>;
return (
<div className="home">
<HomeTable setPokemonId={handleSelectPokemonId} />
<HomeCard pokemonId={selectedPokemonId} />
</div>
);
};

export default Home;
Loading

0 comments on commit 67f4b05

Please sign in to comment.