├── public ├── _redirects ├── mobile.png ├── webSite.png └── index.html ├── src ├── assets │ ├── logo.png │ └── shopping.png ├── index.js ├── index.css ├── components │ ├── Toasts.js │ ├── Loader.js │ ├── BarItems.js │ ├── NavBar.js │ ├── ProductItem.js │ ├── DetailItem.js │ └── CardItem.js ├── pages │ ├── Contact.js │ ├── Details.js │ ├── Favorites.js │ ├── Products.js │ └── ShoppingCard.js ├── App.js └── context │ └── ProductContext.js ├── .idea ├── .gitignore ├── modules.xml └── e-commerce-clothes.iml ├── .gitignore ├── README.md └── package.json /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 2 | -------------------------------------------------------------------------------- /public/mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yusufdeepwork/react-eCommerce-clothes/HEAD/public/mobile.png -------------------------------------------------------------------------------- /public/webSite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yusufdeepwork/react-eCommerce-clothes/HEAD/public/webSite.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yusufdeepwork/react-eCommerce-clothes/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/shopping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yusufdeepwork/react-eCommerce-clothes/HEAD/src/assets/shopping.png -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import EcommerceProvider from './context/ProductContext'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | 11 | 12 | , 13 | document.getElementById('root'), 14 | ); 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /.idea/e-commerce-clothes.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/components/Toasts.js: -------------------------------------------------------------------------------- 1 | export const getAddCardToast = (product, addToast) => { 2 | addToast(`added shopping card :${product.description}`, { 3 | appearance: 'success', 4 | autoDismiss: true, 5 | }); 6 | }; 7 | export const removeFavoriteToast = (product, addToast) => { 8 | addToast(`removed favorite :${product.description}`, { 9 | appearance: 'info', 10 | autoDismiss: true, 11 | }); 12 | }; 13 | export const addFavoriteToast = (product, addToast) => { 14 | addToast(`add favorite :${product.description}`, { 15 | appearance: 'success', 16 | autoDismiss: true, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # e-Commerce - Clothes Web Site 2 | `🌟` You can see all of clothes and find your style.\ 3 | `🌟` If you like a clothes, you can add to your card.\ 4 | `🌟` You maybe dont want to buy immediately, you can add favorites it.\ 5 | `🌟` Find your style, enjoy shopping. 6 | 7 | # Website Preview 8 | ## Desktop Preview 9 | ![Image of e-Commerce](public/webSite.png) 10 | ## Mobile Preview 11 | ![Image of e-Commerce](public/mobile.png) 12 | 13 | 14 | 15 | ## Contribute 16 | 17 | In the project directory, you can run: 18 | 19 | ### `yarn start` 20 | 21 | Runs the app in the development mode.\ 22 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 23 | 24 | -------------------------------------------------------------------------------- /src/components/Loader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ContentLoader from 'react-content-loader'; 3 | 4 | const Loader = () => { 5 | const createContentLoader = () => ( 6 | 13 | 14 | 15 | ); 16 | return ( 17 | <> 18 | {createContentLoader()} 19 | {createContentLoader()} 20 | {createContentLoader()} 21 | {createContentLoader()} 22 | {createContentLoader()} 23 | {createContentLoader()} 24 | 25 | ); 26 | }; 27 | 28 | export default Loader; 29 | -------------------------------------------------------------------------------- /src/pages/Contact.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const Favorites = () => ( 5 | 6 | Dont hesitate to contact our, We work for your style. 7 | Adress: Turkey/Antalya 8 | Email: awesome@suits.com 9 | 10 | ); 11 | export default Favorites; 12 | const ContactInfos = styled.div` 13 | font-family: "Fira Code Medium",monospace; 14 | display: flex; 15 | height: 80vh; 16 | font-size:50px; 17 | font-weight: bold; 18 | justify-content: space-evenly; 19 | align-items: center; 20 | text-align: center; 21 | flex-direction: column; 22 | transition: 1s; 23 | animation-name: example; 24 | animation-duration: 5s; 25 | cursor: default; 26 | color: deepskyblue; 27 | @keyframes example { 28 | from {color: black;} 29 | to {color: deepskyblue;} 30 | } 31 | @media screen and (max-width: 770px){ 32 | font-size: 30px; 33 | } 34 | `; 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e-commerce-clothes", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "axios": "^0.21.1", 7 | "react": "^17.0.2", 8 | "react-alert": "^7.0.3", 9 | "react-alert-template-basic": "^1.0.2", 10 | "react-content-loader": "^6.0.3", 11 | "react-dom": "^17.0.2", 12 | "react-icons": "^4.2.0", 13 | "react-router-dom": "^5.2.0", 14 | "react-scripts": "4.0.3", 15 | "react-toast-notifications": "^2.4.4", 16 | "styled-components": "^5.3.0", 17 | "web-vitals": "^1.0.1" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/pages/Details.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from 'react'; 2 | import { useParams } from 'react-router-dom'; 3 | import axios from 'axios'; 4 | import { CartProductsContainer } from './ShoppingCard'; 5 | import DetailItem from '../components/DetailItem'; 6 | import { ProductContext } from '../context/ProductContext'; 7 | 8 | const Details = () => { 9 | const [detailItem, setDetailItem] = useState(); 10 | const dynamicUrl = useParams(); 11 | const { id } = dynamicUrl; 12 | const apiUrl = `https://60bfb0e797295a0017c4398c.mockapi.io/clothesImage/${id}`; 13 | const { favorites } = useContext(ProductContext); 14 | useEffect(() => { 15 | axios.get(apiUrl).then((response) => { 16 | setDetailItem(response.data); 17 | }).catch((err) => { 18 | console.log(err); 19 | }); 20 | }, [id]); 21 | const favorite = !!favorites.find((favoriteItem) => favoriteItem.id === id); 22 | return ( 23 | 24 | 25 | 26 | ); 27 | }; 28 | export default Details; 29 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from 'react'; 2 | import { Switch, Route, Redirect } from 'react-router-dom'; 3 | import { ProductContext } from './context/ProductContext'; 4 | import NavBar from './components/NavBar'; 5 | import BarItems from './components/BarItems'; 6 | import Products from './pages/Products'; 7 | import Favorites from './pages/Favorites'; 8 | import ShoppingCard from './pages/ShoppingCard'; 9 | import Details from './pages/Details'; 10 | import Contact from './pages/Contact'; 11 | 12 | function App() { 13 | const { isBarActive } = useContext(ProductContext); 14 | useEffect(() => { 15 | }, [isBarActive]); 16 | 17 | return ( 18 | <> 19 | 20 | {isBarActive ? : null} 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | } 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /src/pages/Favorites.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import styled from 'styled-components'; 3 | import { ProductsContainer } from './Products'; 4 | import { ProductContext } from '../context/ProductContext'; 5 | import ProductItem from '../components/ProductItem'; 6 | 7 | const Favorites = () => { 8 | const { favorites } = useContext(ProductContext); 9 | return ( 10 | favorites.length === 0 ? ( 11 | 12 | You Dont have favorite Product yet. 13 | You can look products. We are sure you will love. 14 | 15 | ) : ( 16 | 17 | {favorites.map((favorite) => )} 18 | 19 | ) 20 | 21 | ); 22 | }; 23 | export default Favorites; 24 | const NoFavorite = styled.div` 25 | font-family: "Fira Code Medium",monospace; 26 | display: flex; 27 | height: 80vh; 28 | font-size:50px; 29 | font-weight: bold; 30 | justify-content: space-evenly; 31 | align-items: center; 32 | color: black; 33 | text-align: center; 34 | flex-direction: column; 35 | @media screen and (max-width: 770px){ 36 | font-size: 30px; 37 | } 38 | `; 39 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 15 | 24 | Clothes Shop 25 | 26 | 27 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/components/BarItems.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import styled from 'styled-components'; 3 | import { NavLink as Link } from 'react-router-dom'; 4 | import { ProductContext } from '../context/ProductContext'; 5 | 6 | const BarItems = () => { 7 | const { isBarActive, setIsBarActive } = useContext(ProductContext); 8 | const onChangeBar = (active) => setIsBarActive(!active); 9 | return ( 10 | 11 | onChangeBar(isBarActive)} to="/card" activeStyle> 12 |

Shopping Card

13 |
14 | onChangeBar(isBarActive)} to="/favorites" activeStyle> 15 |

Favorites

16 |
17 | onChangeBar(isBarActive)} to="/contact" activeStyle> 18 |

Contact

19 |
20 |
21 | ); 22 | }; 23 | export default BarItems; 24 | 25 | const BarItemContainer = styled.nav` 26 | display: flex; 27 | text-align: center; 28 | justify-content: space-between; 29 | font-size: 20px; 30 | padding:0 12vw; 31 | flex-direction: column; 32 | @media screen and (max-width: 768px){ 33 | padding: 0; 34 | } 35 | 36 | `; 37 | 38 | const BarItem = styled(Link)` 39 | color: white; 40 | display: flex; 41 | border-bottom: cornflowerblue solid 1px; 42 | align-items: center; 43 | justify-content: center; 44 | text-align: center; 45 | text-decoration: none; 46 | padding: 0 1rem; 47 | background: darkblue; 48 | &.active { 49 | color:white ; 50 | } 51 | transition: all 0.2s ease-in-out; 52 | :hover{ 53 | background: cornflowerblue; 54 | } 55 | `; 56 | -------------------------------------------------------------------------------- /src/pages/Products.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from 'react'; 2 | import styled from 'styled-components'; 3 | import axios from 'axios'; 4 | import Loader from '../components/Loader'; 5 | import ProductItem from '../components/ProductItem'; 6 | import { ProductContext } from '../context/ProductContext'; 7 | 8 | const Products = () => { 9 | const apiUrl = 'https://60bfb0e797295a0017c4398c.mockapi.io/clothesImage'; 10 | const { data, setData, favorites } = useContext(ProductContext); 11 | 12 | useEffect(() => { 13 | axios.get(apiUrl).then((response) => { 14 | setData(response.data); 15 | }).catch((err) => { 16 | // eslint-disable-next-line no-console 17 | console.log(err); 18 | }); 19 | }, []); 20 | return ( 21 | <> 22 | 23 | {data.length !== 0 24 | ? data.map((product) => ( 25 | favoriteItem.id === product.id)} 29 | /> 30 | 31 | )) 32 | : } 33 | 34 | 35 | ); 36 | }; 37 | export default Products; 38 | export const ProductsContainer = styled.div` 39 | display: grid; 40 | grid-template-columns: repeat(3, 1fr); 41 | grid-gap: 2rem; 42 | grid-auto-rows: 50rem; 43 | grid-auto-columns: 40rem; 44 | text-align: center; 45 | -ms-grid-column-align: center; 46 | -ms-grid-row-align: center; 47 | align-self: center; 48 | padding: 1rem 2rem; 49 | @media screen and (max-width: 1300px){ 50 | grid-template-columns: repeat(2, 1fr); 51 | grid-auto-rows: 30rem; 52 | } 53 | @media screen and (max-width: 768px){ 54 | grid-template-columns: repeat(1, 1fr); 55 | grid-auto-rows: 35rem; 56 | } 57 | @media screen and (max-width: 600px){ 58 | grid-auto-rows: 30rem; 59 | } 60 | `; 61 | -------------------------------------------------------------------------------- /src/pages/ShoppingCard.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import styled from 'styled-components'; 3 | import { useAlert } from 'react-alert'; 4 | import { ProductContext } from '../context/ProductContext'; 5 | import CardItem from '../components/CardItem'; 6 | 7 | const ShoppingCard = () => { 8 | const currency = ' TRY'; 9 | const { productsInCard } = useContext(ProductContext); 10 | const alert = useAlert(); 11 | const calculateTotalPayment = () => { 12 | let sum = 0; 13 | // eslint-disable-next-line no-unused-expressions 14 | productsInCard ? productsInCard.forEach((item) => { 15 | sum += parseInt(item.price, 10) * item.count; 16 | }) : null; 17 | return sum; 18 | }; 19 | const totalPayment = calculateTotalPayment() 20 | return ( 21 | 22 | 23 | 24 | Shopping Total Payment : 25 | {` ${totalPayment}`} 26 | {currency} 27 | 28 | {totalPayment ? alert.error('We are sorry, we are closed. Please Try again after.')} 31 | > 32 | Pay 33 | : null} 34 | 35 | {productsInCard.map((product) => )} 36 | 37 | ); 38 | }; 39 | export default ShoppingCard; 40 | export const CartProductsContainer = styled.div` 41 | cursor: default; 42 | display: flex; 43 | justify-content: center; 44 | flex-direction: column; 45 | text-align: center; 46 | align-items: center; 47 | padding: 1vw 5vw; 48 | `; 49 | const TotalPayment = styled.div` 50 | width: 90%; 51 | height: 10rem; 52 | color: cornflowerblue; 53 | display: flex; 54 | justify-content: space-evenly; 55 | font-size:60px; 56 | align-items:center; 57 | text-align:center; 58 | background-color: lightcyan; 59 | border-radius: 100rem; 60 | margin-top: 5px; 61 | @media screen and (max-width: 600px){ 62 | border-radius: 3rem; 63 | } 64 | `; 65 | const TotalPaymentText = styled.text` 66 | font-size: 40px; 67 | font-family: "Fira Code Medium",monospace; 68 | text-align: center; 69 | @media screen and (max-width: 600px){ 70 | font-size: 20px; 71 | } 72 | `; 73 | const PayButton = styled.button` 74 | text-align: center; 75 | font-size: 40px; 76 | font-family: "Helvetica Neue",monospace; 77 | margin-right: 5rem; 78 | height: 4rem; 79 | width: 10rem; 80 | border-radius: 10rem; 81 | color: white; 82 | background: darkblue; 83 | :hover{ 84 | background: red; 85 | cursor: pointer; 86 | transition: 0.5s; 87 | border: red solid 1px; 88 | } 89 | @media screen and (max-width: 600px){ 90 | font-size: 25px; 91 | margin: 2vw; 92 | } 93 | `; 94 | -------------------------------------------------------------------------------- /src/context/ProductContext.js: -------------------------------------------------------------------------------- 1 | import React, { createContext, useState, useEffect } from 'react'; 2 | import { ToastProvider } from 'react-toast-notifications'; 3 | import { positions, Provider as AlertProvider } from 'react-alert'; 4 | import AlertTemplate from 'react-alert-template-basic'; 5 | import { BrowserRouter } from 'react-router-dom'; 6 | 7 | export const ProductContext = createContext(undefined, undefined); 8 | 9 | const eCommerceApp = ({ children }) => { 10 | const [isBarActive, setIsBarActive] = useState(false); 11 | const [favorites, setFavorites] = useState([]); 12 | const [productsInCard, setProductsInCard] = useState([]); 13 | const [data, setData] = useState([]); 14 | 15 | useEffect(() => { 16 | }, [isBarActive]); 17 | 18 | const addFavorite = (favoriteProduct) => { 19 | const copyFavoriteArray = [...favorites]; 20 | const isInProduct = copyFavoriteArray.map((copyProduct) => copyProduct.id) 21 | .includes(favoriteProduct.id); 22 | if (!isInProduct && favorites) { 23 | setFavorites((prevFavorites) => [...prevFavorites, favoriteProduct]); 24 | } 25 | }; 26 | 27 | const removeFavorite = (removedfavorite) => { 28 | const copyFavoriteArray = [...favorites]; 29 | const isInProduct = copyFavoriteArray.map((copyProduct) => copyProduct.id) 30 | .includes(removedfavorite.id); 31 | if (isInProduct && favorites) { 32 | setFavorites(copyFavoriteArray.filter((item) => item.id !== removedfavorite.id)); 33 | } 34 | }; 35 | const changeItem = (willChangeProduct, favorite) => { 36 | if (favorite) { 37 | removeFavorite(willChangeProduct); 38 | } else { 39 | addFavorite(willChangeProduct); 40 | } 41 | }; 42 | 43 | const addCard = (willAddCardProduct) => { 44 | const { 45 | id, price, clothesUrl, description, 46 | } = willAddCardProduct; 47 | if (productsInCard.length === 0) { 48 | setProductsInCard([{ 49 | id, count: 1, price, clothesUrl, description, 50 | }]); 51 | } else if (productsInCard.find((item) => item.id === id)) { 52 | // eslint-disable-next-line max-len 53 | const updatedCard = productsInCard.map((item) => (item.id === id ? { ...item, count: item.count + 1 } : item)); 54 | setProductsInCard(updatedCard); 55 | } else { 56 | setProductsInCard((prevState) => [...prevState, { 57 | id, count: 1, price, clothesUrl, description, 58 | }]); 59 | } 60 | }; 61 | return ( 62 | 75 | 76 | 77 | 78 | {children} 79 | 80 | 81 | 82 | 83 | ); 84 | }; 85 | export default eCommerceApp; 86 | -------------------------------------------------------------------------------- /src/components/NavBar.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from 'react'; 2 | import styled from 'styled-components'; 3 | import { NavLink as Link } from 'react-router-dom'; 4 | import { FaBars } from 'react-icons/fa'; 5 | import logo from '../assets/logo.png'; 6 | import shoppingCart from '../assets/shopping.png'; 7 | import { ProductContext } from '../context/ProductContext'; 8 | 9 | const NavBar = () => { 10 | const { isBarActive, setIsBarActive, productsInCard } = useContext(ProductContext); 11 | useEffect(() => { 12 | 13 | }, [productsInCard]); 14 | const calculateTotalPayment = () => { 15 | let sum = 0; 16 | // eslint-disable-next-line no-unused-expressions 17 | productsInCard.length !== 0 ? productsInCard.forEach((item) => { 18 | sum += parseInt(item.price, 10) * item.count; 19 | }) : null; 20 | return sum; 21 | }; 22 | return ( 23 | 41 | ); 42 | }; 43 | export default NavBar; 44 | 45 | const Nav = styled.nav` 46 | background: #000; 47 | display: flex; 48 | text-align: center; 49 | justify-content: space-between; 50 | height: 6rem; 51 | font-size: 20px; 52 | padding:0 12vw; 53 | 54 | @media screen and (max-width: 768px){ 55 | padding: 0; 56 | } 57 | `; 58 | const NavMenu = styled.nav` 59 | display: flex; 60 | align-items: center; 61 | `; 62 | 63 | const NavLink = styled(Link)` 64 | color: white; 65 | display: flex; 66 | align-items: center; 67 | text-decoration: none; 68 | padding: 0 1rem; 69 | 70 | &.active { 71 | color:aquamarine ; 72 | } 73 | transition: all 0.2s ease-in-out; 74 | @media screen and (max-width: 768px){ 75 | display: ${(({ active }) => (active ? 'none' : null))} 76 | } 77 | `; 78 | const Bars = styled(FaBars)` 79 | justify-content: center; 80 | align-items: center; 81 | cursor: pointer; 82 | display: none; 83 | color: #fff; 84 | @media screen and (max-width: 768px) { 85 | display: flex; 86 | } 87 | width: 2.5rem; 88 | height: 100%; 89 | margin-right: 20px; 90 | `; 91 | const ProductCardText = styled.h1` 92 | font-size: 24px; 93 | color: royalblue; 94 | padding: 1rem; 95 | 96 | text-align: center; 97 | align-items: center; 98 | transition: 2s; 99 | margin-right: 10px; 100 | animation-name: example; 101 | animation-duration: 2s; 102 | cursor: default; 103 | border-radius: 10rem; 104 | background-color: lightblue; 105 | @keyframes example { 106 | from {color: red;} 107 | to {color: royalblue;} 108 | } 109 | @media screen and (max-width: 1500px){ 110 | font-size: 15px; 111 | padding: 0.2rem; 112 | width: 6rem; 113 | } 114 | `; 115 | -------------------------------------------------------------------------------- /src/components/ProductItem.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import styled from 'styled-components'; 3 | import { Link } from 'react-router-dom'; 4 | import { useToasts } from 'react-toast-notifications'; 5 | import { ProductContext } from '../context/ProductContext'; 6 | import { addFavoriteToast, getAddCardToast, removeFavoriteToast } from './Toasts'; 7 | 8 | const ProductItem = ({ product, favorite }) => { 9 | const { addCard, changeItem } = useContext(ProductContext); 10 | const { addToast } = useToasts(); 11 | 12 | return ( 13 | 14 | 15 | 16 | 17 | {product.price} TRY 18 | 19 | 20 | 21 | { 23 | addCard(product); 24 | getAddCardToast(product, addToast); 25 | }} 26 | > 27 | Add To Cart 28 | 29 | See Details 30 | { 32 | changeItem(product, favorite); 33 | // eslint-disable-next-line no-unused-expressions 34 | favorite ? removeFavoriteToast(product, addToast) 35 | : addFavoriteToast(product, addToast); 36 | }} 37 | > 38 | 39 | {favorite ? 'Remove From Favorites ' : 'Add To Favorites'} 40 | 41 | 42 | 43 | ); 44 | }; 45 | export default ProductItem; 46 | 47 | const ProductCart = styled.div` 48 | display: flex; 49 | text-align: center; 50 | justify-content: center; 51 | align-items: center; 52 | flex-direction: column; 53 | border-radius: 30px; 54 | background-color: ${({favorite}) => favorite ? `lightcyan`: `#f2f2f2` }; 55 | color: deepskyblue; 56 | `; 57 | const ProductImage = styled.img` 58 | padding: 1rem 0 0 0; 59 | height: 80%; 60 | width: 80%; 61 | justify-content: center; 62 | align-items: center; 63 | object-fit: contain; 64 | @media screen and (max-width: 768px) and (min-width: 500px){ 65 | width: 25rem; 66 | } 67 | `; 68 | const InfoProduct = styled.text` 69 | display: flex; 70 | padding: 0.5rem; 71 | font-size: 20px; 72 | font-family: "Helvetica Neue",monospace; 73 | justify-content: space-between; 74 | background-color: snow; 75 | margin-bottom:5px; 76 | border-radius:10rem; 77 | 78 | :hover{ 79 | transition: 0.1s; 80 | color: blue; 81 | cursor: pointer; 82 | background-color: #5cf0ff; 83 | } 84 | @media screen and (max-width: 1300px){ 85 | font-size: 1rem; 86 | padding: 0 0.5rem; 87 | } 88 | `; 89 | const ProductBar = styled.div` 90 | display: flex; 91 | justify-content: center; 92 | align-items: center; 93 | margin: 0 10px; 94 | 95 | `; 96 | 97 | const ProductPrice = styled.text` 98 | 99 | padding: 1rem; 100 | font-size: 1.5rem; 101 | font-family: "Helvetica Neue",monospace; 102 | justify-content: space-between; 103 | color: black; 104 | @media screen and (max-width: 1300px){ 105 | font-size: 1rem; 106 | padding: 0.5rem 0 0.5rem 0; 107 | } 108 | `; 109 | const ShowingDetails = styled(Link)` 110 | display: flex; 111 | padding: 0.5rem; 112 | margin: 0 10px 5px 10px; 113 | font-size: 20px; 114 | font-family: "Helvetica Neue",monospace; 115 | justify-content: space-between; 116 | background-color: snow; 117 | border-radius:10rem; 118 | color: deepskyblue; 119 | 120 | :hover{ 121 | transition: 0.1s; 122 | color: blue; 123 | cursor: pointer; 124 | background-color: #5cf0ff; 125 | } 126 | text-decoration: inherit; /* no underline */ 127 | @media screen and (max-width: 1300px){ 128 | font-size: 1rem; 129 | padding: 0 0.5rem; 130 | } 131 | `; 132 | -------------------------------------------------------------------------------- /src/components/DetailItem.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from 'react'; 2 | import styled from 'styled-components'; 3 | import { useToasts } from 'react-toast-notifications'; 4 | import { Link } from 'react-router-dom'; 5 | import { addFavoriteToast, removeFavoriteToast, getAddCardToast } from './Toasts'; 6 | import { ProductContext } from '../context/ProductContext'; 7 | 8 | const DetailItem = ({ product, favorite }) => { 9 | // eslint-disable-next-line no-console 10 | const { addToast } = useToasts(); 11 | const { changeItem, addCard } = useContext(ProductContext); 12 | useEffect(() => { 13 | 14 | }, [product, favorite]); 15 | 16 | return ( 17 | 18 | {/* eslint-disable-next-line react/destructuring-assignment */} 19 | {product ? ( 20 | <> 21 | 22 | 23 | 24 | {product.description} 25 | {`Price : ${product.price}`} 26 | 27 | 28 | { 31 | addCard(product); 32 | getAddCardToast(product, addToast); 33 | }} 34 | > 35 | Add to Card 36 | 37 | { 40 | changeItem(product, favorite); 41 | // eslint-disable-next-line no-unused-expressions 42 | favorite ? removeFavoriteToast(product, addToast) 43 | : addFavoriteToast(product, addToast); 44 | }} 45 | > 46 | {' '} 47 | {favorite ? 'Remove From Favorites ' : 'Add To Favorites'} 48 | 49 | 50 | Back to Products Page 51 | 52 | 53 | 54 | 55 | ) : null} 56 | 57 | 58 | ); 59 | }; 60 | export default DetailItem; 61 | 62 | const DetailProductBox = styled.div` 63 | cursor: default; 64 | display: flex; 65 | width: 90%; 66 | height: 80vh; 67 | margin: 1rem 0; 68 | text-align: center; 69 | justify-content: space-evenly ; 70 | align-items: center; 71 | flex-direction: row; 72 | background-color: #f2f2f2; 73 | border-radius: 4rem; 74 | 75 | 76 | @media screen and (max-width:650px){ 77 | flex-direction: column; 78 | } 79 | @media screen and (max-width:650px){ 80 | height: 85vh; 81 | border-radius: 1rem; 82 | margin: 0; 83 | } 84 | `; 85 | const CartProductImage = styled.img` 86 | height: 90%; 87 | width: 40%; 88 | float: left; 89 | justify-content: center; 90 | align-items: center; 91 | padding: 2rem; 92 | object-fit: contain; 93 | 94 | @media screen and (max-width: 1350px){ 95 | width: 20rem; 96 | } 97 | @media screen and (max-width: 320px){ 98 | width: 15rem; 99 | }@media screen and (max-width: 500px){ 100 | height: 70%; 101 | } 102 | `; 103 | 104 | const DetailInfoProduct = styled.text` 105 | cursor: default; 106 | display: flex; 107 | padding: 1rem; 108 | font-size: 2rem; 109 | font-family: "Helvetica Neue",monospace; 110 | justify-content: space-between; 111 | :hover{ 112 | transition: 0.1s; 113 | color: blue; 114 | cursor: ${({ link }) => (link ? 'pointer' : 'default')}; 115 | } 116 | @media screen and (max-width:1000px){ 117 | font-size: 1.5rem; 118 | } 119 | @media screen and (max-width:650px) { 120 | padding: 0 1rem; font-size: 1rem; 121 | } 122 | @media screen and (max-width:400px) { 123 | font-size: 0.75rem; 124 | } 125 | `; 126 | const DetailProductBar = styled.div` 127 | display: flex; 128 | justify-content: center; 129 | align-items: center; 130 | flex-direction: row; 131 | @media screen and (max-width:1000px) and (min-width: 650px){ 132 | flex-direction: column; 133 | } 134 | 135 | `; 136 | const InfoBar = styled.div` 137 | display: flex; 138 | justify-content: space-between; 139 | align-items: center; 140 | flex-direction: column; 141 | 142 | 143 | `; 144 | const BackHome = styled(Link)` 145 | 146 | color: inherit; /* blue colors for links too */ 147 | text-decoration: inherit; /* no underline */ 148 | 149 | `; 150 | const DetailInfoButton = styled.text` 151 | cursor: default; 152 | display: flex; 153 | padding: 1rem; 154 | margin: 10px 5px; 155 | font-size: 1.5rem; 156 | font-family: "Helvetica Neue",monospace; 157 | justify-content: space-between; 158 | background-color: snow; 159 | color: deepskyblue; 160 | border-radius:10rem; 161 | :hover{ 162 | transition: 0.1s; 163 | color: blue; 164 | cursor: pointer; 165 | background-color: #5cf0ff; 166 | } 167 | @media screen and (max-width:1000px){ 168 | font-size: 1.5rem; 169 | } 170 | @media screen and (max-width:650px) { 171 | padding: 0 1rem; font-size: 1rem; 172 | } 173 | @media screen and (max-width:400px) { 174 | padding: 0 1rem; font-size: 0.75rem; 175 | } 176 | `; 177 | -------------------------------------------------------------------------------- /src/components/CardItem.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import styled from 'styled-components'; 3 | import { useToasts } from 'react-toast-notifications'; 4 | import { FaPlus, FaMinus } from 'react-icons/fa'; 5 | import { NavLink as Link } from 'react-router-dom'; 6 | import { ProductContext } from '../context/ProductContext'; 7 | 8 | const CardItem = ({ product }) => { 9 | const { 10 | productsInCard, setProductsInCard, 11 | } = useContext(ProductContext); 12 | const { addToast } = useToasts(); 13 | 14 | const changeItem = (isAdd) => { 15 | if (!isAdd) { 16 | addToast(`decreased | removed from shopping card :${product.description}`, { 17 | appearance: 'error', 18 | autoDismiss: true, 19 | }); 20 | } else { 21 | addToast(`add to shopping card :${product.description}`, { 22 | appearance: 'success', 23 | autoDismiss: true, 24 | }); 25 | } 26 | }; 27 | 28 | const increaseProductInCard = () => { 29 | const { id } = product; 30 | if (productsInCard.find((item) => item.id === id)) { 31 | // eslint-disable-next-line max-len 32 | const updatedCard = productsInCard.map((item) => (item.id === id ? { ...item, count: item.count + 1 } : item)); 33 | setProductsInCard(updatedCard); 34 | } 35 | }; 36 | 37 | const decreaseProductInCard = () => { 38 | const { id } = product; 39 | if (productsInCard.find((item) => item.id === id)) { 40 | // eslint-disable-next-line max-len 41 | const updatedCard = productsInCard.map((item) => (item.id === id ? { ...item, count: item.count - 1 } : item)); 42 | setProductsInCard(updatedCard.filter((item) => item.count !== 0)); 43 | } 44 | }; 45 | 46 | const getTotalPrice = () => { 47 | const { id } = product; 48 | const searchedProduct = productsInCard.find((item) => item.id === id); 49 | return searchedProduct.price * searchedProduct.count; 50 | }; 51 | 52 | return ( 53 | 54 | 55 | 56 | {`Product Price : ${product.price} | Total Price: ${getTotalPrice()}`} 57 | {product.description} 58 | See Details 59 | 60 | 61 | 62 | { 63 | increaseProductInCard(); 64 | changeItem(true); 65 | }} 66 | /> 67 | 68 | {productsInCard.find((item) => item.id === product.id).count} 69 | 70 | { 71 | decreaseProductInCard(); 72 | changeItem(false); 73 | }} 74 | /> 75 | 76 | 77 | 78 | 79 | ); 80 | }; 81 | 82 | export default CardItem; 83 | 84 | const CardBox = styled.div` 85 | cursor: default; 86 | display: flex; 87 | width: 90%; 88 | height: 30rem; 89 | text-align: center; 90 | justify-content: space-between; 91 | align-items: center; 92 | flex-direction: row; 93 | background-color: #f2f2f2; 94 | border-radius: 4rem; 95 | margin: 20px 0px; 96 | @media screen and (max-width: 425px){ 97 | height: 20rem; 98 | } 99 | 100 | `; 101 | const CartProductImage = styled.img` 102 | height: 90%; 103 | width: 20%; 104 | float: left; 105 | justify-content: center; 106 | align-items: center; 107 | padding: 2rem; 108 | object-fit: contain; 109 | @media screen and (max-width: 1350px){ 110 | width: 20rem; 111 | } 112 | @media screen and (max-width: 600px){ 113 | display: none; 114 | } 115 | `; 116 | const InfoProduct = styled.text` 117 | cursor: default; 118 | display: flex; 119 | padding: 1rem; 120 | font-size: 20px; 121 | font-family: "Helvetica Neue",monospace; 122 | justify-content: space-between; 123 | 124 | @media screen and (max-width: 1300px){ 125 | font-size: 1rem; 126 | padding: 0 0.5rem; 127 | } 128 | `; 129 | const ProductBar = styled.div` 130 | display: flex; 131 | justify-content: center; 132 | align-items: center; 133 | flex-direction: column; 134 | `; 135 | 136 | const ProductPrice = styled.text` 137 | 138 | padding: 1rem; 139 | font-size: 1.5rem; 140 | font-family: "Helvetica Neue",monospace; 141 | justify-content: space-between; 142 | 143 | @media screen and (max-width: 1300px){ 144 | font-size: 1rem; 145 | padding: 0.5rem 0 0.5rem 0; 146 | } 147 | `; 148 | const CardChanges = styled.div` 149 | display: flex; 150 | justify-content: space-evenly; 151 | align-items: center; 152 | flex-direction: column; 153 | margin: 3rem; 154 | font-size: 30px; 155 | padding: 1rem; 156 | @media screen and (max-width: 710px){ 157 | font-size: 20px; 158 | padding: 0; 159 | margin: 0; 160 | } 161 | `; 162 | const ChangeItem = styled.div` 163 | display: flex; 164 | padding: 1rem; 165 | font-size: 30px; 166 | font-family: "Helvetica Neue",monospace; 167 | justify-content: space-between; 168 | :hover{ 169 | transition: 0.1s; 170 | color: blue; 171 | cursor: pointer; 172 | } 173 | 174 | `; 175 | const ShowDetails = styled(Link)` 176 | display: flex; 177 | align-items: center; 178 | text-decoration: none; 179 | padding: 1rem 1rem; 180 | font-size: 20px; 181 | font-family: "Fira Code Medium",monospace; 182 | margin: 10px; 183 | background-color: lightpink; 184 | 185 | &.active { 186 | color:aquamarine ; 187 | 188 | } 189 | border-radius:10rem; 190 | color: black; 191 | 192 | :hover{ 193 | transition: 0.1s; 194 | color: blue; 195 | cursor: pointer; 196 | background-color: #5cf0ff; 197 | } 198 | transition: all 0.2s ease-in-out; 199 | @media screen and (min-width: 600px){ 200 | display: none; 201 | } 202 | `; 203 | const ProductCardCount = styled.text` 204 | cursor: default; 205 | font-size: 70px; 206 | color: black; 207 | margin: 1.5rem 0; 208 | font-family: "Fira Code Medium",serif; 209 | @media screen and (max-width: 700px){ 210 | font-size: 50px; 211 | margin: 10px; 212 | } 213 | ` 214 | --------------------------------------------------------------------------------