From db339fdd20ca8476dd6dbf326d5b3ac6541b6cea Mon Sep 17 00:00:00 2001 From: Fabio Benedetti Date: Wed, 26 May 2021 22:15:54 +0200 Subject: [PATCH 1/3] feat: cart --- .eslintrc | 4 +- src/ShoppingCart/ShoppingCart.js | 56 +++++++++++++++++++++++++++- src/ShoppingCart/components/Card.js | 39 +++++++++++++++++++ src/ShoppingCart/components/Hr.js | 6 +++ src/ShoppingCart/components/Total.js | 22 +++++++++++ src/ShoppingCart/constants.js | 1 + 6 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 src/ShoppingCart/components/Card.js create mode 100644 src/ShoppingCart/components/Hr.js create mode 100644 src/ShoppingCart/components/Total.js create mode 100644 src/ShoppingCart/constants.js diff --git a/.eslintrc b/.eslintrc index 90eb58a..9cf914a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -8,6 +8,8 @@ "prettier" ], "rules": { + "react/jsx-props-no-spreading": 0, + "react/prop-types": 0, "semi": 0, "jsx-a11y/click-events-have-key-events": 0, "jsx-a11y/no-static-element-interactions": 0, @@ -25,4 +27,4 @@ } ] } -} +} \ No newline at end of file diff --git a/src/ShoppingCart/ShoppingCart.js b/src/ShoppingCart/ShoppingCart.js index 920a490..bc84934 100644 --- a/src/ShoppingCart/ShoppingCart.js +++ b/src/ShoppingCart/ShoppingCart.js @@ -1,3 +1,57 @@ +import styled from "styled-components"; +import { GRAY } from "./constants"; +import { Card } from "./components/Card"; +import { Total } from "./components/Total"; + +const LayoutStyle = styled.div` + display: grid; + grid-template-columns: 2fr 1fr; + max-width: 1024px; + background-color: ${GRAY}; + margin: auto; +`; + +const PanelStyle = styled.div` + margin: 1rem; + background-color: white; + padding: 1rem; +`; +const MOCK = { + img: + "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/1.png", + name: "BULBASAUR", + type: "Grass", + price: 64, + quantity: 1, +}; + +const MockItems = []; +// eslint-disable-next-line no-plusplus +for (let i = 0; i < 30; i++) { + MockItems.push(MOCK); +} + +const ScrollStyle = styled.div` + overflow-y: scroll; + max-height: 500px; +`; + export function ShoppingCart() { - return
ShoppingCart
; + return ( + + +

Place you order (1 article)

+ + {MockItems.map((item) => ( + + ))} + +
+ + acc + current.price, 0)} + /> + +
+ ); } diff --git a/src/ShoppingCart/components/Card.js b/src/ShoppingCart/components/Card.js new file mode 100644 index 0000000..82f1969 --- /dev/null +++ b/src/ShoppingCart/components/Card.js @@ -0,0 +1,39 @@ +import styled from "styled-components"; +import { GRAY } from "../constants"; +import { HRStyle } from "./Hr"; + +const CardStyle = styled.div` + display: grid; + grid-template-columns: 1fr 3fr 1fr; + img { + width: 100px; + background-color: ${GRAY}; + } + div { + padding: 1rem; + } +`; + +const CardPriceStyle = styled.div` + padding: 1rem; + display: flex; + flex-direction: column; + align-items: flex-end; +`; + +export const Card = ({ name, img, type, price, quantity }) => ( + <> + + {name} +
+

{name}

+

{type}

+
+ +

{quantity}

+

{price}

+
+
+ + +); diff --git a/src/ShoppingCart/components/Hr.js b/src/ShoppingCart/components/Hr.js new file mode 100644 index 0000000..cfb9b66 --- /dev/null +++ b/src/ShoppingCart/components/Hr.js @@ -0,0 +1,6 @@ +import styled from "styled-components"; +import { GRAY } from "../constants"; + +export const HRStyle = styled.hr` + border: 0.5px solid ${GRAY}; +`; diff --git a/src/ShoppingCart/components/Total.js b/src/ShoppingCart/components/Total.js new file mode 100644 index 0000000..3ffc356 --- /dev/null +++ b/src/ShoppingCart/components/Total.js @@ -0,0 +1,22 @@ +import styled from "styled-components"; +import { HRStyle } from "./Hr"; + +const TotalItemStyle = styled.div` + display: flex; + justify-content: space-between; +`; + +export const Total = ({ total }) => ( +
+

Total

+ + Subtotal + {(total * 0.8).toFixed(2)} + + + + Total (VAT included) + {total} + +
+); diff --git a/src/ShoppingCart/constants.js b/src/ShoppingCart/constants.js new file mode 100644 index 0000000..e412307 --- /dev/null +++ b/src/ShoppingCart/constants.js @@ -0,0 +1 @@ +export const GRAY = `#efeff0`; From c13a15abf252444a1be4167ab3c879c26dd87e7a Mon Sep 17 00:00:00 2001 From: Fabio Benedetti Date: Sat, 29 May 2021 10:16:49 +0200 Subject: [PATCH 2/3] feat: integrate details --- .eslintrc | 1 - src/App.js | 3 -- src/Details/components/MetaSection/index.js | 4 +- src/Details/index.js | 17 +++++++- src/ShoppingCart/ShoppingCart.js | 45 ++++++++++++--------- src/ShoppingCart/components/Card.js | 13 +++++- src/ShoppingCart/components/Total.js | 24 +++++++++++ src/common/pokemonStorage.js | 23 +++++++++++ 8 files changed, 101 insertions(+), 29 deletions(-) create mode 100644 src/common/pokemonStorage.js diff --git a/.eslintrc b/.eslintrc index 9cf914a..846eabb 100644 --- a/.eslintrc +++ b/.eslintrc @@ -9,7 +9,6 @@ ], "rules": { "react/jsx-props-no-spreading": 0, - "react/prop-types": 0, "semi": 0, "jsx-a11y/click-events-have-key-events": 0, "jsx-a11y/no-static-element-interactions": 0, diff --git a/src/App.js b/src/App.js index b243f8b..1aa8b96 100644 --- a/src/App.js +++ b/src/App.js @@ -79,9 +79,6 @@ const App = () => {
  • Home
  • -
  • - ShoppingCart -
  • Order Completed
  • diff --git a/src/Details/components/MetaSection/index.js b/src/Details/components/MetaSection/index.js index a11714c..cce07ee 100644 --- a/src/Details/components/MetaSection/index.js +++ b/src/Details/components/MetaSection/index.js @@ -58,7 +58,7 @@ const SubTitle = styled.h3` border-bottom: 1px solid grey; `; -const MetaSection = ({ type, name, price, stats, abilities }) => ( +const MetaSection = ({ type, name, price, stats, abilities, onAddToCart }) => ( {titleCase(type)} {titleCase(name)} @@ -67,7 +67,7 @@ const MetaSection = ({ type, name, price, stats, abilities }) => ( {price} ¥ VAT included - Add to bag + Add to bag Stats diff --git a/src/Details/index.js b/src/Details/index.js index 2f50530..ee6be28 100644 --- a/src/Details/index.js +++ b/src/Details/index.js @@ -1,11 +1,12 @@ /* eslint-disable react/prop-types */ import { useEffect, useState } from "react"; -import { useParams } from "react-router-dom"; +import { useParams, useHistory } from "react-router-dom"; import styled from "styled-components"; import { DetailsLayout } from "./components/DetailsLayout"; import { ImageSection } from "./components/ImageSection"; import { ThumbnailSection } from "./components/ThumbnailSection"; import { MetaSection } from "./components/MetaSection"; +import { addToCart } from "../common/pokemonStorage"; const CrossSellingSection = styled.div` grid-area: crossselling; @@ -19,6 +20,7 @@ export function Details() { const [data, setData] = useState(null); const [selectedImage, setSelectedImage] = useState(""); + const history = useHistory(); useEffect(() => { fetch(`https://pokeapi.co/api/v2/pokemon/${id}`) .then((res) => res.json()) @@ -31,6 +33,18 @@ export function Details() { }); }, [id]); + const handleAdd = () => { + addToCart({ + img: data.sprites.other["official-artwork"].front_default, + name: data.name, + type: data.types[0].type.name, + price: data.base_experience, + quantity: 1, + }); + + history.push(`/shopping-cart`); + }; + if (!data) { return Loading; } @@ -59,6 +73,7 @@ export function Details() { price={data.base_experience} stats={data.stats} abilities={data.abilities} + onAddToCart={handleAdd} /> diff --git a/src/ShoppingCart/ShoppingCart.js b/src/ShoppingCart/ShoppingCart.js index bc84934..1f1a7f8 100644 --- a/src/ShoppingCart/ShoppingCart.js +++ b/src/ShoppingCart/ShoppingCart.js @@ -1,7 +1,9 @@ import styled from "styled-components"; +import { useState } from "react"; import { GRAY } from "./constants"; import { Card } from "./components/Card"; import { Total } from "./components/Total"; +import { getCartItems, removeFromCart } from "../common/pokemonStorage"; const LayoutStyle = styled.div` display: grid; @@ -16,20 +18,6 @@ const PanelStyle = styled.div` background-color: white; padding: 1rem; `; -const MOCK = { - img: - "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/1.png", - name: "BULBASAUR", - type: "Grass", - price: 64, - quantity: 1, -}; - -const MockItems = []; -// eslint-disable-next-line no-plusplus -for (let i = 0; i < 30; i++) { - MockItems.push(MOCK); -} const ScrollStyle = styled.div` overflow-y: scroll; @@ -37,20 +25,37 @@ const ScrollStyle = styled.div` `; export function ShoppingCart() { + const [cart, setCart] = useState(getCartItems()); + + const handleRemove = (name) => { + setCart(removeFromCart(name)); + }; + if (cart.length === 0) { + return ( + + +

    Your cart is empty

    {" "} +
    +
    + ); + } + return ( -

    Place you order (1 article)

    +

    Place you order ({cart.length} article)

    - {MockItems.map((item) => ( - + {cart.map((item) => ( + handleRemove(item.name)} + /> ))}
    - acc + current.price, 0)} - /> + acc + current.price, 0)} />
    ); diff --git a/src/ShoppingCart/components/Card.js b/src/ShoppingCart/components/Card.js index 82f1969..3c476fd 100644 --- a/src/ShoppingCart/components/Card.js +++ b/src/ShoppingCart/components/Card.js @@ -21,13 +21,22 @@ const CardPriceStyle = styled.div` align-items: flex-end; `; -export const Card = ({ name, img, type, price, quantity }) => ( +const RemoveStyle = styled.a` + color: black; + cursor: pointer; + &:hover { + text-decoration: underline; + } +`; + +export const Card = ({ name, img, type, price, quantity, onRemove }) => ( <> {name}
    -

    {name}

    + {name}

    {type}

    + Remove

    {quantity}

    diff --git a/src/ShoppingCart/components/Total.js b/src/ShoppingCart/components/Total.js index 3ffc356..7900a0c 100644 --- a/src/ShoppingCart/components/Total.js +++ b/src/ShoppingCart/components/Total.js @@ -6,6 +6,28 @@ const TotalItemStyle = styled.div` justify-content: space-between; `; +const CheckoutButton = styled.button` + font-family: inherit; + font-size: 100%; + line-height: 1.15; + font-weight: 700; + margin: 24px 0 32px 0; + width: 100%; + background-color: black; + color: white; + outline: none; + display: inline-flex; + justify-content: center; + border: 0; + cursor: pointer; + padding: 24px 0; + + align-self: end; + &:hover { + opacity: 0.8; + } +`; + export const Total = ({ total }) => (

    Total

    @@ -18,5 +40,7 @@ export const Total = ({ total }) => ( Total (VAT included) {total} + + Checkout
    ); diff --git a/src/common/pokemonStorage.js b/src/common/pokemonStorage.js new file mode 100644 index 0000000..7fb7ea4 --- /dev/null +++ b/src/common/pokemonStorage.js @@ -0,0 +1,23 @@ +const STORAGE_KEY = "cart"; + +export const getCartItems = () => { + try { + const cartStorage = localStorage.getItem(STORAGE_KEY); + return JSON.parse(cartStorage); + } catch (e) { + return []; + } +}; + +export const addToCart = (item) => { + const cartStorage = getCartItems(); + cartStorage.push(item); + localStorage.setItem(STORAGE_KEY, JSON.stringify(cartStorage)); +}; + +export const removeFromCart = (name) => { + const cartStorage = getCartItems(); + const filteredCart = cartStorage.filter((c) => c.name !== name); + localStorage.setItem(STORAGE_KEY, JSON.stringify(filteredCart)); + return filteredCart; +}; From 203d9bae8b26708110859648899cd992d534424d Mon Sep 17 00:00:00 2001 From: navya Date: Sun, 6 Jun 2021 22:33:02 +0200 Subject: [PATCH 3/3] with checkout and order confirmation --- src/App.js | 1 + src/Checkout/Checkout.js | 6 ++- src/Checkout/components/Form.jsx | 80 ++++++++++++++++++++++++++++ src/Details/index.js | 3 +- src/OrderCompleted/OrderCompleted.js | 67 ++++++++++++++++++++++- src/ShoppingCart/ShoppingCart.js | 9 +++- src/ShoppingCart/components/Total.js | 7 ++- src/common/customerInfo.js | 13 +++++ src/common/pokemonStorage.js | 3 ++ 9 files changed, 181 insertions(+), 8 deletions(-) create mode 100644 src/Checkout/components/Form.jsx create mode 100644 src/common/customerInfo.js diff --git a/src/App.js b/src/App.js index 1aa8b96..3082d3e 100644 --- a/src/App.js +++ b/src/App.js @@ -67,6 +67,7 @@ const App = () => { setIsLoading(false); }) .catch((e) => { + // eslint-disable-next-line console.log(e); setIsLoading(false); }); diff --git a/src/Checkout/Checkout.js b/src/Checkout/Checkout.js index baceed3..a92f3a0 100644 --- a/src/Checkout/Checkout.js +++ b/src/Checkout/Checkout.js @@ -1,3 +1,7 @@ +import Form from "./components/Form"; + export function Checkout() { - return
    Checkout
    ; + return
    +
    +
    ; } diff --git a/src/Checkout/components/Form.jsx b/src/Checkout/components/Form.jsx new file mode 100644 index 0000000..039e12b --- /dev/null +++ b/src/Checkout/components/Form.jsx @@ -0,0 +1,80 @@ +import React, {useState} from 'react' +import { useHistory } from "react-router-dom"; +import styled from 'styled-components' +import {setCustomerDetail} from "../../common/customerInfo" + +const FormWrapper = styled.div` + margin-bottom: 2rem; + max-width: 1000px; + margin: auto; + background-color: black; + color: white; + justify-content: centre; + align-item: center; +`; +const PanelStyle = styled.div` + margin: 2rem; + background-color: white; + padding: 2rem; + display: block; +`; +const FormLayout = styled.form` + display: block; + margin: 2px; +`; +const Label = styled.label` + font-weight: 20px; + color: black; + display: block; +`; +const Input = styled.input` + width: 100px; + height: 15px; +`; +const Address = styled.textarea` +width: 100px; + height: 15px +`; +const SubmitButton = styled.button` + width : 60px; + height: 30px; + display: block; + margin: 5px; +`; + + +function Form() { + const [customer, setCustomer] = useState(); + const history = useHistory(); + const handleChange = (e)=>{ + const name=e.target.value; + setCustomer(name); + setCustomerDetail(name); + } +const handleSubmit = () =>{ + history.push(`/order-completed`); +} + + return ( + +

    CHECKOUT

    + + + + handleChange(e)}/> + + + + + +
    + + + SUBMIT + + + + ) +} +export default Form + diff --git a/src/Details/index.js b/src/Details/index.js index ee6be28..e4cb178 100644 --- a/src/Details/index.js +++ b/src/Details/index.js @@ -40,8 +40,7 @@ export function Details() { type: data.types[0].type.name, price: data.base_experience, quantity: 1, - }); - + }) history.push(`/shopping-cart`); }; diff --git a/src/OrderCompleted/OrderCompleted.js b/src/OrderCompleted/OrderCompleted.js index ecb8cf3..cfb0399 100644 --- a/src/OrderCompleted/OrderCompleted.js +++ b/src/OrderCompleted/OrderCompleted.js @@ -1,3 +1,68 @@ +import styled from 'styled-components' +import {getCustomerDetail} from '../common/customerInfo' +import {getCartItems} from '../common/pokemonStorage' + +const Wrapper = styled.div` + margin: 5px; + width: 550px; + background-color: #ffffcc ; +`; +const Message = styled.h4` + padding: 10px; + display: flex; +`; +const ScrollStyle = styled.div` + overflow-y: scroll; + max-height: 500px; + width: 500px; +`; +const CardStyle = styled.div` + display: grid; + grid-template-columns: 1fr 3fr 1fr; + img { + width: 100px; + background-color: cream; + } + div { + padding: 1rem; + } +`; + +const CardPriceStyle = styled.div` + padding: 1rem; + display: flex; + flex-direction: column; + align-items: flex-end; +`; +const Card = ({name, img, type, price, quantity}) =>( + + {name} +
    + {name} +

    {type}

    +
    + +

    {quantity}

    {price}

    +
    +
    +); export function OrderCompleted() { - return
    OrderCompleted
    ; + const customerName = getCustomerDetail(); + const cart= getCartItems(); + return ( + + Hello {customerName} your order was successfully placed, Thank You for Shopping with us!! +
    + ORDERED LIST + + {cart.map((item) => ( + + ))} +
    TOTAL AMOUNT={cart.reduce((acc, current) => acc + current.price, 0)}
    +
    +
    + ); } diff --git a/src/ShoppingCart/ShoppingCart.js b/src/ShoppingCart/ShoppingCart.js index 1f1a7f8..6dc7d9a 100644 --- a/src/ShoppingCart/ShoppingCart.js +++ b/src/ShoppingCart/ShoppingCart.js @@ -1,5 +1,6 @@ import styled from "styled-components"; import { useState } from "react"; +import { useHistory } from "react-router-dom"; import { GRAY } from "./constants"; import { Card } from "./components/Card"; import { Total } from "./components/Total"; @@ -26,10 +27,14 @@ const ScrollStyle = styled.div` export function ShoppingCart() { const [cart, setCart] = useState(getCartItems()); - + const history = useHistory(); const handleRemove = (name) => { setCart(removeFromCart(name)); }; + + const handleCheckout = () =>{ + history.push(`/checkout`); + } if (cart.length === 0) { return ( @@ -55,7 +60,7 @@ export function ShoppingCart() { - acc + current.price, 0)} /> + acc + current.price, 0)} handleCheckout= {handleCheckout} /> ); diff --git a/src/ShoppingCart/components/Total.js b/src/ShoppingCart/components/Total.js index 7900a0c..afef1ac 100644 --- a/src/ShoppingCart/components/Total.js +++ b/src/ShoppingCart/components/Total.js @@ -1,6 +1,7 @@ import styled from "styled-components"; import { HRStyle } from "./Hr"; + const TotalItemStyle = styled.div` display: flex; justify-content: space-between; @@ -28,7 +29,9 @@ const CheckoutButton = styled.button` } `; -export const Total = ({ total }) => ( + + +export const Total = ({ total, handleCheckout }) => (

    Total

    @@ -41,6 +44,6 @@ export const Total = ({ total }) => ( {total} - Checkout + Checkout
    ); diff --git a/src/common/customerInfo.js b/src/common/customerInfo.js new file mode 100644 index 0000000..71c3740 --- /dev/null +++ b/src/common/customerInfo.js @@ -0,0 +1,13 @@ +const STORAGE_KEY ='name'; +export const setCustomerDetail = (name) =>{ + sessionStorage.setItem(STORAGE_KEY, name); +} + +export const getCustomerDetail = () =>{ + const customerDetails=sessionStorage.getItem(STORAGE_KEY); + if(customerDetails===null){ + return []; + } + return (customerDetails); + +} \ No newline at end of file diff --git a/src/common/pokemonStorage.js b/src/common/pokemonStorage.js index 7fb7ea4..c2d0d37 100644 --- a/src/common/pokemonStorage.js +++ b/src/common/pokemonStorage.js @@ -3,6 +3,9 @@ const STORAGE_KEY = "cart"; export const getCartItems = () => { try { const cartStorage = localStorage.getItem(STORAGE_KEY); + if(cartStorage === null){ + return []; + } return JSON.parse(cartStorage); } catch (e) { return [];