Skip to content

Commit

Permalink
refactor: fix small bugs and reformat
Browse files Browse the repository at this point in the history
  • Loading branch information
wleklinskimateusz committed Apr 27, 2024
1 parent 41811dd commit 8fbea8f
Show file tree
Hide file tree
Showing 26 changed files with 296 additions and 338 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,28 @@
An app that displays pokemons and information about them

## Technology

- React.js
- Typescript
- Sass
- SCSS
- Redux

## Setup
- clone repository and in the root directory run

- clone repository and in the root directory run

```bash
npm install
```

## Run in Development

- to start in development run

```bash
npm run start
```

## Live

- to see a live version of an app go to: https://wleklinskimateusz.github.io/pokedex/
16 changes: 15 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"react-scripts": "5.0.0",
"react-table": "^7.7.0",
"sass": "^1.49.9",
"typescript": "~4.1.5"
"typescript": "~4.1.5",
"zod": "^3.23.4"
},
"scripts": {
"predeploy": "npm run build",
Expand All @@ -38,8 +39,8 @@
]
},
"devDependencies": {
"@testing-library/react": "^12.1.4",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^7.2.1",
"@types/jest": "^24.9.1",
"@types/node": "^12.20.47",
Expand All @@ -48,4 +49,4 @@
"@types/react-redux": "^7.1.23",
"@types/react-table": "^7.7.10"
}
}
}
68 changes: 33 additions & 35 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import { useEffect, useState } from "react";
import styles from "./App.module.scss";
import { Pokemon } from "./types/Pokemon";
import { Table } from "./components/Table/Table";
Expand All @@ -11,57 +11,55 @@ import classNames from "classnames";
import { DarkThemeToggle } from "./components/DarkThemeToggle/DarkThemeToggle";
import { RootState } from "./app/store";

const loadingText = "Catching them...";
const idleText = "Bring Me MORE Pokemons!";

const getCounterValue = (state: RootState) => state.counter.value;


export default function App() {
const [current, setCurrent] = useState<Pokemon>();
const dispatch = useAppDispatch();
// const tab = useAppSelector(getCounterValue);

const tab = useAppSelector(getCounterValue);
const status = useAppSelector((state) => state.counter.status);
const dark = useAppSelector((state) => state.darkMode.dark);

useEffect(() => {
dispatch(AddPokemons(0));
}, [dispatch]);



useEffect(() => {
if (status === "failed") {
alert("An Error Has occured")
}
}, [status])
useAlertIfFetchFail(status);
const { fetchNext } = useFetchPokemons(tab);

return (
<div className={classNames([styles.App, { bg: !dark, "bg-dark": dark }])}>
<div className={classNames([styles.App, "bg"])}>
<DarkThemeToggle />
<Counter pokemons={tab.length} />
<header
className={classNames([
styles.App__header,
{ bg: !dark, "bg-dark": dark },
])}
>
<header className={classNames([styles.App__header, "bg"])}>
<h1>Pokedex</h1>
<Button
onClick={() => {
dispatch(AddPokemons(tab.length));
}}
>
{status === "loading" ? loadingText : idleText}
<Button onClick={fetchNext}>
{status === "loading"
? "Catching them..."
: "Bring Me MORE Pokemons!"}
</Button>
</header>
<main className={styles.App__main}>
<Table rawData={tab} onClick={setCurrent} />
{!!current && (
<Box pokemon={current} reset={() => setCurrent(undefined)} />
)}
<Box pokemon={current} reset={() => setCurrent(undefined)} />
</main>
</div>
);
}

function useAlertIfFetchFail(status: RootState["counter"]["status"]) {
useEffect(() => {
if (status === "failed") {
alert("Could not fetch pokemons. Try again later.");
}
}, [status]);
}

function useFetchPokemons(tab: Pokemon[]) {
const dispatch = useAppDispatch();

useEffect(() => {
dispatch(AddPokemons(0));
}, [dispatch]);

return {
fetchNext: () => {
dispatch(AddPokemons(tab.length));
},
};
}
5 changes: 2 additions & 3 deletions src/app/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from './store';
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
3 changes: 3 additions & 0 deletions src/app/selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { RootState } from "./store";

export const darkModeSelector = (state: RootState) => state.darkMode.dark;
8 changes: 4 additions & 4 deletions src/app/store.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import darkModeSlice from '../features/darkModeSlice';
import pokemonSlice from '../features/pokemonSlice';
import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
import darkModeSlice from "../features/darkModeSlice";
import pokemonSlice from "../features/pokemonSlice";

export const store = configureStore({
reducer: {
counter: pokemonSlice,
darkMode: darkModeSlice
darkMode: darkModeSlice,
},
});

Expand Down
32 changes: 16 additions & 16 deletions src/components/Box/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
import React, { FC } from "react";
import { FC } from "react";
import { Pokemon } from "../../types/Pokemon";
import styles from "./Box.module.scss";
import { BoxItem } from "../BoxItem/BoxItem";
import classNames from "classnames";
import { useAppSelector } from "../../app/hooks";
import { RootState } from "../../app/store";

interface IBox {
pokemon: Pokemon;
type BoxProps = {
pokemon?: Pokemon;
reset: () => void;
}
};

export const Box: FC<IBox> = ({ pokemon, reset }) => {
const dark = useAppSelector((state: RootState) => state.darkMode.dark);
export const Box: FC<BoxProps> = ({ pokemon, reset }) => {
if (!pokemon) return null;
return (
<div
className={classNames([
styles.Box,
{ primary: !dark, "primary-dark": dark },
])}
>
<div className={classNames([styles.Box, "primary"])}>
<div onClick={reset} className={styles.Box__close}>
x
</div>
<div className={styles.Box__header}>
<img src={pokemon.sprite} width={150} alt={pokemon.name} />
{pokemon.name}
</div>
<div className={classNames([styles.Box__body])}>
<div className={styles.Box__body}>
<ul>
<BoxItem label="Type">{pokemon.type.join(", ")}</BoxItem>
<BoxItem label="Height">{pokemon.height}</BoxItem>
Expand All @@ -37,3 +29,11 @@ export const Box: FC<IBox> = ({ pokemon, reset }) => {
</div>
);
};

const BoxItem: FC<{
label: string;
}> = ({ label, children }) => (
<li>
<span>{label}</span>: {children}
</li>
);
13 changes: 0 additions & 13 deletions src/components/BoxItem/BoxItem.tsx

This file was deleted.

22 changes: 11 additions & 11 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React, { FC } from "react";
import { FC, HTMLAttributes } from "react";
import styles from "./Button.module.scss";
import classNames from "classnames";
import { useAppSelector } from "../../app/hooks";
import { RootState } from "../../app/store";

interface IButton {
onClick: () => void;
}

export const Button: FC<IButton> = ({ children, onClick }) => {
const dark = useAppSelector((state: RootState) => state.darkMode.dark)
export const Button: FC<HTMLAttributes<HTMLButtonElement>> = ({
children,
className,
...rest
}) => {
return (
<div onClick={onClick} className={classNames([styles.Button, {secondary: !dark, "secondary-dark": dark}])}>
<button
className={classNames([styles.Button, "secondary", className])}
{...rest}
>
{children}
</div>
</button>
);
};
23 changes: 13 additions & 10 deletions src/components/Counter/Counter.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import classNames from "classnames";
import React, { FC } from "react";
import { useAppSelector } from "../../app/hooks";
import { RootState } from "../../app/store";
import { FC } from "react";
import styles from "./Counter.module.scss";

interface ICounter {
pokemons: number
}

type CounterProps = {
pokemons: number;
};

export const Counter:FC<ICounter> = ({pokemons}) => {
const dark = useAppSelector((state: RootState) => state.darkMode.dark)
return <div className={styles.Counter}><h3>Your Pokemons:</h3><div className={classNames([styles.Counter__number, {primary: !dark, "primary-dark": dark}])}>{pokemons}</div></div>;
export const Counter: FC<CounterProps> = ({ pokemons }) => {
return (
<div className={styles.Counter}>
<h3>Your Pokemons:</h3>
<div className={classNames([styles.Counter__number, "primary"])}>
{pokemons}
</div>
</div>
);
};
8 changes: 8 additions & 0 deletions src/components/DarkThemeToggle/DarkThemeHandler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ReactNode } from "react";
import { useAppSelector } from "../../app/hooks";
import { darkModeSelector } from "../../app/selectors";

export const DarkThemeHandler = ({ children }: { children: ReactNode }) => {
const dark = useAppSelector(darkModeSelector);
return <div className={dark ? "dark" : "light"}>{children}</div>;
};
15 changes: 8 additions & 7 deletions src/components/DarkThemeToggle/DarkThemeToggle.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React, { FC } from "react";
import { FC } from "react";
import { toggle } from "../../features/darkModeSlice";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { RootState } from "../../app/store";
import { Icon } from "../Icon";
import { useAppDispatch } from "../../app/hooks";
import { Icon } from "./Icon";
import styles from "./DarkThemeToggle.module.scss";
import classNames from "classnames";

export const DarkThemeToggle: FC = () => {
const dispatch = useAppDispatch();
const dark = useAppSelector((state: RootState) => state.darkMode.dark);
return (
<div className={classNames([styles.DarkThemeToggle, {primary: !dark, "primary-dark": dark}])} onClick={() => dispatch(toggle())}>
<Icon dark={dark} />
<div
className={classNames([styles.DarkThemeToggle, "primary"])}
onClick={() => dispatch(toggle())}
>
<Icon />
</div>
);
};
Loading

0 comments on commit 8fbea8f

Please sign in to comment.