From b54d52ed3ca06769378613eff5461575f51996d0 Mon Sep 17 00:00:00 2001 From: Pavel Zabolotny Date: Mon, 4 Jan 2021 20:40:04 +0300 Subject: [PATCH] HT3 --- src/components/basket/basket.js | 49 ++++++++++ src/components/basket/basket.module.css | 18 ++++ src/components/basket/index.js | 1 + src/components/order/index.js | 1 + src/components/order/order.js | 46 +++++++++ src/components/order/order.module.css | 113 ++++++++++++++++++++++ src/components/restaurants/restaurants.js | 2 + src/redux/actions.js | 3 +- src/redux/constants.js | 1 + src/redux/reducers/order.js | 9 +- 10 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 src/components/basket/basket.js create mode 100644 src/components/basket/basket.module.css create mode 100644 src/components/basket/index.js create mode 100644 src/components/order/index.js create mode 100644 src/components/order/order.js create mode 100644 src/components/order/order.module.css diff --git a/src/components/basket/basket.js b/src/components/basket/basket.js new file mode 100644 index 0000000..f46e059 --- /dev/null +++ b/src/components/basket/basket.js @@ -0,0 +1,49 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import Order from '../order'; +import styles from './basket.module.css'; + +export const basket = ({ restaurants, orderProduct }) => { + if (Object.keys(orderProduct).length === 0) { + return ( +
+
Basket is empty
+
+ ); + } + + let products = restaurants.reduce( + (accumulator, currentValue) => [...accumulator, ...currentValue.menu], + [] + ); + + let orderProducts = products.filter((product) => orderProduct[product.id]); + + let totalPrice = `${orderProducts.reduce( + (accumulator, currentValue) => + accumulator + orderProduct[currentValue.id] * currentValue.price, + 0 + )}$`; + + return ( +
+
Basket
+
+ {orderProducts.map((product) => ( + + ))} +
+
+ Total price: {totalPrice} +
+
+ ); +}; + +const mapStateToProps = (state) => { + return { + orderProduct: state.order, + }; +}; + +export default connect(mapStateToProps)(basket); diff --git a/src/components/basket/basket.module.css b/src/components/basket/basket.module.css new file mode 100644 index 0000000..8cab1c5 --- /dev/null +++ b/src/components/basket/basket.module.css @@ -0,0 +1,18 @@ +.basket { + padding: 32px; + border-top: 1px solid var(--black); + border-bottom: 1px solid var(--black); +} +.title { + text-align: center; + margin-bottom: 16px; +} +.totalPrice { + margin-top: 16px; + padding: 0 32px; + font-weight: 300; + font-size: 24px; +} +.totalPrice span { + font-weight: 500; +} diff --git a/src/components/basket/index.js b/src/components/basket/index.js new file mode 100644 index 0000000..d9c6b0c --- /dev/null +++ b/src/components/basket/index.js @@ -0,0 +1 @@ +export { default } from './basket'; diff --git a/src/components/order/index.js b/src/components/order/index.js new file mode 100644 index 0000000..0bc73e4 --- /dev/null +++ b/src/components/order/index.js @@ -0,0 +1 @@ +export { default } from './order'; diff --git a/src/components/order/order.js b/src/components/order/order.js new file mode 100644 index 0000000..857225b --- /dev/null +++ b/src/components/order/order.js @@ -0,0 +1,46 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import styles from './order.module.css'; +import { decrement, increment, remove } from '../../redux/actions'; + +const Order = ({ product, amount, increment, decrement, remove }) => { + return ( +
+
+
+

{product.name}

+
{product.price} $
+
+ Sum price: {product.price * amount}$ +
+
+
+
{amount}
+
+ + + +
+
+
+
+ ); +}; + +const mapStateToProps = (state, ownProps) => ({ + amount: state.order[ownProps.product.id] || 0, +}); + +const mapDispatchToProps = (dispatch, ownProps) => ({ + increment: () => dispatch(increment(ownProps.product.id)), + decrement: () => dispatch(decrement(ownProps.product.id)), + remove: () => dispatch(remove(ownProps.product.id)), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Order); diff --git a/src/components/order/order.module.css b/src/components/order/order.module.css new file mode 100644 index 0000000..b04a4b5 --- /dev/null +++ b/src/components/order/order.module.css @@ -0,0 +1,113 @@ +.product { + padding: 16px 32px; + background: rgba(240, 173, 78, 0.1); + margin-bottom: 8px; +} + +.content { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.productName { + font-size: 18px; + line-height: 28px; + font-weight: 600; + margin-top: 0; + margin-bottom: 8px; +} + +.productPrice { + margin-top: 8px; + font-size: 18px; + line-height: 28px; + font-weight: 600; + color: var(--yellow); +} + +.productControls { + padding: 5px 0; + text-align: center; + display: inline-block; +} + +.productCount { + color: var(--grey-dark); + font-weight: 600; + margin-bottom: 5px; + font-size: 18px; + line-height: 28px; +} + +.buttons { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: auto; +} + +.button { + color: var(--white); + background-color: var(--yellow); + border: 1px solid var(--yellow); + border-radius: 2px; + width: 36px; + height: 36px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 0; + font-weight: 700; + font-size: 24px; + outline: none; + box-shadow: none; + cursor: pointer; + margin: 0 1px; +} + +.button:hover, +.button:focus, +.button:active { + border-color: var(--yellow-light); + background-color: var(--yellow-light); +} + +.buttonRemove { + color: var(--white); + background-color: rgba(255, 0, 0, 0.6); + border: 1px solid rgba(255, 0, 0, 0.6); + border-radius: 2px; + width: 36px; + height: 36px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 0; + font-weight: 700; + font-size: 24px; + outline: none; + box-shadow: none; + cursor: pointer; + margin: 0 1px; +} + +.buttonRemove:hover, +.buttonRemove:focus, +.buttonRemove:active { + border-color: rgba(255, 0, 0, 0.4); + background-color: rgba(255, 0, 0, 0.4); +} + +.footer { + padding-top: 16px; + display: flex; + justify-content: flex-end; +} + +.productSumPrice { + font-size: 20px; +} diff --git a/src/components/restaurants/restaurants.js b/src/components/restaurants/restaurants.js index e815cb3..540be80 100644 --- a/src/components/restaurants/restaurants.js +++ b/src/components/restaurants/restaurants.js @@ -2,6 +2,7 @@ import React, { useState, useMemo } from 'react'; import PropTypes from 'prop-types'; import Restaurant from '../restaurant'; import Navigation from '../navigation'; +import Basket from '../basket'; const Restaurants = ({ restaurants }) => { const [activeRestaurantId, setActiveRestaurant] = useState(restaurants[0].id); @@ -17,6 +18,7 @@ const Restaurants = ({ restaurants }) => { restaurants={restaurants} onRestaurantClick={setActiveRestaurant} /> + ); diff --git a/src/redux/actions.js b/src/redux/actions.js index 2807b77..1403ee9 100644 --- a/src/redux/actions.js +++ b/src/redux/actions.js @@ -1,4 +1,5 @@ -import { INCREMENT, DECREMENT } from './constants'; +import { INCREMENT, DECREMENT, REMOVE } from './constants'; export const increment = (id) => ({ type: INCREMENT, payload: { id } }); export const decrement = (id) => ({ type: DECREMENT, payload: { id } }); +export const remove = (id) => ({ type: REMOVE, payload: { id } }); diff --git a/src/redux/constants.js b/src/redux/constants.js index 930d9ef..9cfa25d 100644 --- a/src/redux/constants.js +++ b/src/redux/constants.js @@ -1,2 +1,3 @@ export const INCREMENT = 'INCREMENT'; export const DECREMENT = 'DECREMENT'; +export const REMOVE = 'REMOVE'; diff --git a/src/redux/reducers/order.js b/src/redux/reducers/order.js index 3d83bb4..980b0ed 100644 --- a/src/redux/reducers/order.js +++ b/src/redux/reducers/order.js @@ -1,4 +1,4 @@ -import { DECREMENT, INCREMENT } from '../constants'; +import { DECREMENT, INCREMENT, REMOVE } from '../constants'; // { [productId]: amount } export default (state = 0, action) => { @@ -7,7 +7,14 @@ export default (state = 0, action) => { case INCREMENT: return { ...state, [payload.id]: (state[payload.id] || 0) + 1 }; case DECREMENT: + if (state[payload.id] === undefined || state[payload.id] - 1 <= 0) { + delete state[payload.id]; + return { ...state }; + } return { ...state, [payload.id]: (state[payload.id] || 0) - 1 }; + case REMOVE: + delete state[payload.id]; + return { ...state }; default: return state; }