Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kirill Kostin #13

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
11,586 changes: 11,586 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

41 changes: 41 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "final-project",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.3",
"@testing-library/user-event": "^13.5.0",
"axios": "^0.26.1",
"prop-types": "^15.8.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^6.2.2",
"react-scripts": "5.0.0",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
29 changes: 29 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>pokedex</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@500&display=swap" rel="stylesheet">
</head>
<body>
<!--
<nav class="nav">
<button class="nav__button reset-button-style">Main page</button>
<button class="nav__button reset-button-style">Your pokes</button>
</nav>-->
<main id="root"></main>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.

You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.

To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
102 changes: 102 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, {useState} from 'react';
import MainPage from './main page/MainPage.js';
import axios from 'axios';
import PokesPage from './pokes page/PokesPage';
import MyPokes from './My pokes/MyPokes';
import {DataContext} from './data';
import {Route, Link, Routes} from 'react-router-dom';

export default function App(){
const [countOfPokes, setCountOfPokes] = useState(0);
const [allPokes, setAllPokes] = useState([]);
const [listOfPokes, setListOfPokes] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [caughtPokes, setCaughtPokes] = useState([]);
const [cardsPerPage] = useState(10);
const [url, setUrl] = useState(`https://pokeapi.co/api/v2/pokemon?limit=${cardsPerPage}`)

React.useEffect(function(){
axios.get(url).then(response=>{
setCountOfPokes(response.data.count);
let data = response.data.results.map((item, index)=> ({
id:(index+(currentPage-1)*cardsPerPage),
name:item.name,
url:item.url,
key:(index+(currentPage-1)*cardsPerPage),
caught:false,
caughtDate:null}));
if (!allPokes.find(item=>item.id===data[0].id)){
let count = allPokes.concat(data);
setAllPokes(count);
setListOfPokes(data);
}
else {
let array = [];
for (let i=data[0].id; i<(data[0].id+10); i++){
array.push(allPokes.find(item=>item.id===i))
}
setListOfPokes(array);
}
})
},[,currentPage]);

const [pokesIdForAxios, setPokesIdForAxios] = React.useState(false);
const [pokesData, setPokesData] = React.useState(null);
const getPokesProperties = id => {setPokesIdForAxios(id-((currentPage-1)*cardsPerPage)+1)};

React.useEffect(function(){
if (pokesIdForAxios){
if (pokesIdForAxios<1){
return 0;
}
axios.get(listOfPokes[pokesIdForAxios-1].url).then(response=>{
let dataAboutPoke = {};
Object.assign(dataAboutPoke, listOfPokes[pokesIdForAxios-1]);
dataAboutPoke.abilities = response.data.abilities.map(item=>item.ability.name);
dataAboutPoke.types = response.data.types.map(item=>item.type.name);
dataAboutPoke.imgUrl = response.data.sprites.other["official-artwork"]["front_default"];
dataAboutPoke.weight = response.data.weight;
setPokesData(dataAboutPoke);
})
}
},[pokesIdForAxios]);

const paginate = pageNumber => {
setCurrentPage(pageNumber);
setUrl(`https://pokeapi.co/api/v2/pokemon?offset=${cardsPerPage*(pageNumber-1)}&limit=${cardsPerPage}`);
};

const addCaughtPoke = myNewPoke => {
let array = caughtPokes.filter(item=>true);
array.push(myNewPoke);
setCaughtPokes(array);
}

const removeCaughtPoke = id => {
let array = caughtPokes.filter(item=>(item.id!=id))
setCaughtPokes(array);
}

const cleanPokesData = () => setPokesData(null);

return (
<>
<header className='header'>
<ul className='header__buttons-wrapper'>
<li className='header__button text'><Link to="/" onClick={cleanPokesData}>Главная</Link></li>
<li className='header__button text'><Link to="/my-pokes" onClick={cleanPokesData}>Мои покемоны</Link></li>
</ul>
</header>
<div className='app'>
<DataContext.Provider value={{listOfPokes, setListOfPokes, currentPage, cardsPerPage, addCaughtPoke, removeCaughtPoke, pokesData, getPokesProperties, currentPage, allPokes, setAllPokes}}>
<Routes>
<Route path="/" element={<MainPage countOfPokes={countOfPokes} paginate={paginate}/>}/>
<Route path="/my-pokes" element={<MyPokes caughtPokes={caughtPokes}/>}/>
<Route path="/pers" element={<PokesPage/>}/>
<Route path="*" element={<MainPage/>}/>
</Routes>
</DataContext.Provider>
</div>
</>
)
}
18 changes: 18 additions & 0 deletions src/My pokes/MyPokes.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.MyPokes{
display: flex;
flex-wrap: wrap;
width: 1200px;
}

@media (max-width: 767.9px){
.MyPokes{
width: 100vw;
}
}

@media (min-width: 768px) and (max-width: 1279.9px){
.MyPokes{
width: 100vw;
}

}
12 changes: 12 additions & 0 deletions src/My pokes/MyPokes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import './MyPokes.css';
import React from 'react';
import Card from '../card/Card';

export default function MyPokes({caughtPokes}) {
const cardsOfCaughtPokes = caughtPokes.map(item=><Card id={item.id} name={item.name} caught={item.caught} key={item.key}/>)
return (
<div className="MyPokes">
{cardsOfCaughtPokes}
</div>
);
}
68 changes: 68 additions & 0 deletions src/card/Card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import './CardStyle.css';
import React from 'react';
import { DataContext } from '../data';
import {BrowserRouter as Router, Route, Link, Routes, BrowserRouter} from 'react-router-dom';


export default function Card(props) {
const {id, name, caught} = props;
const {listOfPokes, setListOfPokes, currentPage, cardsPerPage, addCaughtPoke, removeCaughtPoke, getPokesProperties, allPokes, setAllPokes} = React.useContext(DataContext);
const [textButton, setTextButton] = React.useState('Поймать');

let array = allPokes.filter(item=>item.id===id);
React.useEffect(function(){
if (array.length===0){
return (<h1>загрузка...</h1>)
}
if (array[0].caught===true){
setTextButton('Отпустить');
}
},[])

const catchPoke = () => {
debugger
let updatedListOfPokes = listOfPokes.filter(item=>true);
let indexOfDataInListOfPokes = id-(currentPage-1)*cardsPerPage;
if (indexOfDataInListOfPokes<0||indexOfDataInListOfPokes>9){
let updatedAllPokes = allPokes.filter(item=>true);
let indexOfDataInAllPokes = allPokes.findIndex(item=>item.id===id);
updatedAllPokes[indexOfDataInAllPokes].caught=false;
updatedAllPokes[indexOfDataInAllPokes].caughtDate=null;
setAllPokes(updatedAllPokes);
removeCaughtPoke(id);
}
else {
if (updatedListOfPokes[indexOfDataInListOfPokes].caught){
updatedListOfPokes[indexOfDataInListOfPokes].caught=false;
updatedListOfPokes[indexOfDataInListOfPokes].caughtDate=null;
removeCaughtPoke(id);
setListOfPokes(updatedListOfPokes);
setTextButton('Поймать');
let updatedAllPokes = allPokes.filter(item=>true);
let indexOfDataInAllPokes = allPokes.findIndex(item=>item.id===id);
updatedAllPokes[indexOfDataInAllPokes].caught=false;
updatedAllPokes[indexOfDataInAllPokes].caughtDate=null;
setAllPokes(updatedAllPokes);
}
else {
updatedListOfPokes[indexOfDataInListOfPokes].caught=true;
updatedListOfPokes[indexOfDataInListOfPokes].caughtDate=new Date();
addCaughtPoke(listOfPokes[indexOfDataInListOfPokes]);
setListOfPokes(updatedListOfPokes);
setTextButton('Отпустить');
}
}
}

return (
<>
<div className="Card" onClick={(e)=> getPokesProperties(id)}>
<Link to="/pers" state={id}>
<h2 className='Card__poke-id'>id={id}</h2>
<h2 className='Card__poke-name'>{name}</h2>
<button onClick={(e)=>{e.preventDefault();catchPoke()}} className='Card__button reset-button-style'>{textButton}</button>
</Link>
</div>
</>
);
}
44 changes: 44 additions & 0 deletions src/card/CardStyle.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.Card{
height: 300px;
flex-basis: 20%;
position: relative;
background-color: #d7d7d7;
border-radius: 20px;

}
.Card>a{
position: absolute;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
text-decoration: none;
}
.Card__poke-name{
font-size: 20px;
font-family: 'Roboto', sans-serif;
}
.Card__button{
font-size: 20px;
width: 60%;
height: 10%;
background-color: aqua;
border-radius: 10px;
}
@media (max-width: 767.9px){
.Card{
flex-basis: 50%;
}
.Card__poke-name{
margin-top: 30px;
}
}

@media (min-width: 768px) and (max-width: 1279.9px){
.Card{
flex-basis: 33%;
}

}
3 changes: 3 additions & 0 deletions src/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import {createContext} from 'react';

export const DataContext = createContext(null);
Loading