Skip to content

Commit

Permalink
Create basket and total price
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanUglovets committed Oct 19, 2021
1 parent 55a5779 commit 64c20f6
Show file tree
Hide file tree
Showing 15 changed files with 240 additions and 69 deletions.
4 changes: 4 additions & 0 deletions .idea/watcherTasks.xml

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

26 changes: 13 additions & 13 deletions public/data.json
Original file line number Diff line number Diff line change
@@ -1,86 +1,86 @@
[
{
"id": 1,
"id": "1",
"src": "https://images.wbstatic.net/c324x432/new/8420000/8423816-1.jpg",
"title": "TERREX AX3 BETA MID",
"subTitle": "adidas",
"price": "253р. 95к."
"price": "2530"
},
{
"id": 2,
"src": "https://images.wbstatic.net/c324x432/new/8210000/8216373-2.jpg",
"title": "TERREX EASTRAIL",
"subTitle": "adidas",
"price": "161р. 59к."
"price": "1610"
},
{
"id": 3,
"src": "https://images.wbstatic.net/c324x432/new/18090000/18097671-1.jpg",
"title": "GEL-SONOMA 6 G-TX",
"subTitle": "asics",
"price": "257р. 46к."
"price": "2570"
},
{
"id": 4,
"src": "https://images.wbstatic.net/c324x432/new/7220000/7222183-1.jpg",
"title": "REEBOK ROYAL HYPERI CBLACK/CDGRY6/NEOCHE",
"subTitle": "Reebook",
"price": "115р. 51к."
"price": "1150"
},
{
"id": 5,
"src": "https://images.wbstatic.net/c324x432/new/18090000/18097670-1.jpg",
"title": "GEL-SONOMA 6 G-TX",
"subTitle": "Reebook",
"price": "175р. 55к."
"price": "1750"
},
{
"id": 6,
"src": "https://images.wbstatic.net/c324x432/new/30300000/30304590-1.jpg",
"title": "TERREX TRAILMAKER M",
"subTitle": "adidas",
"price": "300р. 25к."
"price": "3000"
},
{
"id": 7,
"src": "https://images.wbstatic.net/c324x432/new/30030000/30030467-1.jpg",
"title": "ROYAL BB4500 CBLACK",
"subTitle": "Reebook",
"price": "138р. 50к."
"price": "1380"
},
{
"id": 8,
"src": "https://images.wbstatic.net/c324x432/new/13350000/13359524-1.jpg",
"title": "TERREX AX3 GTX CBLACK",
"subTitle": "adidas",
"price": "253р. 95к."
"price": "2530"
},
{
"id": 9,
"src": "https://images.wbstatic.net/c324x432/new/7220000/7222189-1.jpg",
"title": "ROYAL BB4500 CBLACK",
"subTitle": "Reebook",
"price": "92р. 32к."
"price": "1920"
},
{
"id": 10,
"src": "https://images.wbstatic.net/c324x432/new/34890000/34894849-1.jpg",
"title": "GEL-SANGAKU 2",
"subTitle": "asics",
"price": "122р. 96к."
"price": "1220"
},
{
"id": 11,
"src": "https://images.wbstatic.net/c324x432/new/34990000/34997702-1.jpg",
"title": "GEL-SONOMA 6 G-TX",
"subTitle": "asics",
"price": "257р. 46к."
"price": "2570"
},
{
"id": 12,
"src": "https://images.wbstatic.net/c324x432/new/7220000/7222183-1.jpg",
"title": "TERREX AX4 GTX CBLACK",
"subTitle": "adidas",
"price": "230р. 86к."
"price": "2300"
}
]
37 changes: 26 additions & 11 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
import React, {FC} from "react";
import React, {FC, useEffect} from "react";
import './index.scss'
import {Route, Switch} from "react-router-dom"
import Main from "./pages/Main";
import Basket from "./pages/Basket";
import ErrorPage from "./pages/ErrorPage";
import Header from "./components/Header";
import {Container} from "@mui/material";
import {useDispatch, useSelector} from "react-redux";
import {fetchProducts} from "./redux/actionCreators/fetchProducts";
import {LoadingButton} from "@mui/lab";


const App: FC = () => {
const {isLoading} = useSelector((state: any) => state.items)
const dispatch = useDispatch()

useEffect(() => {
dispatch(fetchProducts())
}, [dispatch])


return (
<main>
<Header/>
<Container maxWidth="lg">
<Switch>
<Route path="/" component={Main} exact/>
<Route path="/basket" component={Basket} exact/>
<Route component={ErrorPage} exact/>
</Switch>
</Container>
</main>
(isLoading ? <LoadingButton/>
:
<main>
<Header/>
<Container maxWidth="lg">
<Switch>
<Route path="/" component={Main} exact/>
<Route path="/basket" component={Basket} exact/>
<Route component={ErrorPage} exact/>
</Switch>
</Container>
</main>
)

)
}

Expand Down
41 changes: 41 additions & 0 deletions src/components/BasketItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, {FC} from 'react'
import {Grid, Paper, Typography} from "@mui/material";
import DeleteIcon from '@mui/icons-material/Delete';
import {IProduct} from "../types/IProduct";
import '../index.scss'
import Button from "@mui/material/Button";
import {useDispatch} from "react-redux";
import {deleteItem} from "../redux/reducers/basketReducer";


interface IBasketProps {
item: IProduct
}


const BasketItem: FC<IBasketProps> = ({item}) => {
const dispatch = useDispatch()
const {title, subTitle, price, src, id} = item

const deleteItemBasket = (id: number) => {
dispatch(deleteItem(id))
}

return (
<Grid item sx={{width: "100%"}} >
<Paper elevation={3} sx={{display: "flex", width: "100%" , justifyContent:"space-between"}}>
<img src={src} alt="sneaker" className="img__basket"/>
<div>
<Typography>{title}</Typography>
<Typography>{subTitle}</Typography>
</div>
<div>
<Typography>{price} руб.</Typography>
<Button onClick={()=>deleteItemBasket(id)}><DeleteIcon /></Button>
</div>
</Paper>
</Grid>
)
}

export default BasketItem;
28 changes: 28 additions & 0 deletions src/components/BasketList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, {FC} from 'react'
import {Grid, Typography} from "@mui/material";
import BasketItem from "./BasketItem";
import {useSelector} from "react-redux";
import {IProduct} from "../types/IProduct";
import {RootState} from "../redux/reducers/rootReducer";

interface IBasketItems{
basketSneakers: IProduct[]
}


const BasketList: FC = () => {
const itemsBasket = useSelector((state: RootState) => state.basketItems.basketSneakers)
return (
(itemsBasket.length) > 0
?
<Grid container spacing={2} sx={{mt: "1rem"}}>
{itemsBasket && itemsBasket.map((basketItem: IProduct) => <BasketItem
key={`${basketItem.id}+${Math.random() * 1000}`} item={basketItem}/>)}
</Grid>
:
<Typography variant="h4" component="span">Cart is empty!</Typography>
)
}


export default BasketList
24 changes: 18 additions & 6 deletions src/components/CardList.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import React, {FC} from "react";
import {Grid} from "@mui/material";
import React, {FC, useState} from "react";
import {Grid, Typography} from "@mui/material";
import CardSneaker from './CardSneaker'
import {useSelector} from "react-redux";
import {IProduct} from "../types/IProduct";
import {RootState} from "../redux/reducers/rootReducer";


const CardList: FC = () => {
const {products} = useSelector((state:any) => state.items)
const products = useSelector((state: RootState) => state.items.products)
return (
<Grid container spacing={3} sx={{mt: "2rem"}} >
{products && products.map((product: IProduct, index: number) => <CardSneaker key={product.id} sneaker={product} index={index}/>)}
</Grid>
<>
<Typography variant="h4" component="h1" sx={{color: "blue", margin: "20px 0 0 20px"}}>Каталог</Typography>
<Grid
container
spacing={3}
sx={{mt: "2rem"}}
alignItems="center"
direction="row"
justifyContent="center">
{products && products.map((product: IProduct) =>
<CardSneaker key={product.id} sneaker={product} />)}
</Grid>
</>
)
}

Expand Down
36 changes: 25 additions & 11 deletions src/components/CardSneaker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React,{FC} from "react";
import React, {FC} from "react";
import {Grid} from "@mui/material";
import Card from '@mui/material/Card';
import CardActions from '@mui/material/CardActions';
Expand All @@ -7,24 +7,33 @@ import CardMedia from '@mui/material/CardMedia';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import {IProduct} from "../types/IProduct";
import {useDispatch} from "react-redux";
import {addToBasket} from "../redux/reducers/basketReducer";
import {useDispatch, useSelector} from "react-redux";
import {addToBasket, deleteItem} from "../redux/reducers/basketReducer";
import {RootState} from "../redux/reducers/rootReducer";

interface IPropsCardSneaker{

interface IPropsCardSneaker {
sneaker: IProduct
index: number
}

const CardSneaker: FC<IPropsCardSneaker> = ({sneaker,index}) => {
const CardSneaker: FC<IPropsCardSneaker> = ({sneaker}) => {
const itemsBasket = useSelector((state:RootState) => state.basketItems.basketSneakers)
const dispatch = useDispatch()
const {subTitle,src,title,price,id} = sneaker;
const {subTitle, src, title, price, id} = sneaker;

const inBasket = itemsBasket.some((item) => item.id === id)

const changeBasket = () => {
const changeBasket = (e: any) => {
e.stopPropagation()
dispatch(addToBasket(sneaker))
}

const deleteFromBasket = (id: number) => {
dispatch(deleteItem(id))
}
return (
<Grid item>
<Card sx={{ maxWidth: 345, minHeight: 650 }}>
<Card sx={{maxWidth: 345, minHeight: 650}}>
<CardMedia
component="img"
alt="sneaker img"
Expand All @@ -39,11 +48,16 @@ const CardSneaker: FC<IPropsCardSneaker> = ({sneaker,index}) => {
{subTitle}
</Typography>
<Typography variant="h5" component="span" color="text.secondary">
{price}
{price} руб.
</Typography>
</CardContent>
<CardActions>
<Button variant="contained" onClick={() => changeBasket()}>Buy</Button>
{inBasket
?
<Button variant="contained" color="warning" sx={{fontSize: "12px"}} onClick={() => deleteFromBasket(id)}>Удалить из корзины</Button>
:
<Button variant="contained" sx={{fontSize: "12px"}} onClick={changeBasket}>В корзину</Button>
}
</CardActions>
</Card>
</Grid>
Expand Down
6 changes: 5 additions & 1 deletion src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import "../index.scss"
import {Link} from "react-router-dom"
import {Container, Typography, AppBar, Toolbar} from "@mui/material";
import ShoppingBasketIcon from '@mui/icons-material/ShoppingBasket';
import {useSelector} from "react-redux";
import {RootState} from "../redux/reducers/rootReducer";


const Header: FC = () => {
const itemsBasket = useSelector((state: RootState) => state.basketItems.basketSneakers)
return (
<AppBar position="static">
<Container maxWidth="lg">
Expand All @@ -14,7 +17,8 @@ const Header: FC = () => {
sx={{flexGrow: 1, display: "block", fontFamily: 'Architects Daughter'}}>
<Link to="/" className="logo__link">Sneaker Shop</Link>
</Typography>
<Link to="/basket" className="basket__link"><ShoppingBasketIcon/></Link>
<Link to="/basket" className="basket__link"><ShoppingBasketIcon /></Link>
{itemsBasket.length > 0 ? <Typography className="count__sneaker" variant="body1" component="span">{itemsBasket.length}</Typography> : null}
</Toolbar>
</Container>
</AppBar>
Expand Down
Loading

0 comments on commit 64c20f6

Please sign in to comment.