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

Ht7 #55

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Ht7 #55

Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions src/components/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import RestaurantsPage from '../../pages/restaurants-page';
import Header from '../header';
import Basket from '../basket';
import { UserProvider } from '../../contexts/user-context';
import CheckOutSuccess from '../basket/checkOutResult/checkoutSuccess';
import CheckOutFail from '../basket/checkOutResult/checkOutFail';

const App = () => {
const [name, setName] = useState('Igor');
Expand All @@ -13,6 +15,8 @@ const App = () => {
<UserProvider value={{ name, setName }}>
<Header />
<Switch>
<Route path="/checkout/error" component={CheckOutFail} />
<Route path="/checkout/success" component={CheckOutSuccess} />
<Route path="/checkout" component={Basket} />
<Route path="/restaurants" component={RestaurantsPage} />
<Route path="/error" component={() => <h1>Error Page</h1>} />
Expand Down
10 changes: 8 additions & 2 deletions src/components/basket/basket-item/basket-item.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import { connect } from 'react-redux';
import { connect, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import cn from 'classnames';
import { increment, decrement, remove } from '../../../redux/actions';
import Button from '../../button';
import styles from './basket-item.module.css';
import { activeCurrencySelector } from '../../../redux/selectors';

function BasketItem({
product,
Expand All @@ -15,6 +16,9 @@ function BasketItem({
decrement,
remove,
}) {
const activeCurrency = useSelector(activeCurrencySelector);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

вот это все вычисление повторяется много раза и его лучше вынести в отдельный файл, я покажу на своей домашке, как это лучше делать

const [currencyName, currencyValue] = Object.entries(activeCurrency)[0];
const localSubTotal = Math.round(subtotal * currencyValue);
return (
<div className={styles.basketItem}>
<div className={styles.name}>
Expand All @@ -28,7 +32,9 @@ function BasketItem({
<span className={styles.count}>{amount}</span>
<Button onClick={increment} icon="plus" secondary small />
</div>
<p className={cn(styles.count, styles.price)}>{subtotal} $</p>
<p className={cn(styles.count, styles.price)}>
{localSubTotal} {currencyName}
</p>
<Button onClick={remove} icon="delete" secondary small />
</div>
</div>
Expand Down
41 changes: 33 additions & 8 deletions src/components/basket/basket.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,54 @@
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { connect, useDispatch, useSelector } from 'react-redux';
import { Link, useHistory } from 'react-router-dom';
import { createStructuredSelector } from 'reselect';
import { CSSTransition, TransitionGroup } from 'react-transition-group';

import './basket.css';
import styles from './basket.module.css';

import Loader from '../loader';
import itemStyles from './basket-item/basket-item.module.css';
import BasketItem from './basket-item';
import Button from '../button';
import { orderProductsSelector, totalSelector } from '../../redux/selectors';
import {
activeCurrencySelector,
orderProductsSelector,
totalSelector,
} from '../../redux/selectors';
import { UserConsumer } from '../../contexts/user-context';
import { checkoutProducts } from '../../redux/actions';

function Basket({ title = 'Basket', total, orderProducts }) {
// const { name } = useContext(userContext);
const activeCurrency = useSelector(activeCurrencySelector);
const [currencyName, currencyValue] = Object.entries(activeCurrency)[0];
const history = useHistory();
const dispatch = useDispatch();
const checkOutState = useSelector((state) => state.checkout);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

используйте отдельно написаные селекторы


const onCheckoutClickHandler = () => {
if (history.location.pathname === '/checkout') {
dispatch(checkoutProducts(orderProducts));
}
};
if (checkOutState.loading) {
return <Loader />;
}
if (checkOutState.loaded) {
history.push('/checkout/success');
Copy link
Owner

@koretskiyav koretskiyav Jan 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

это лучше делать на уровне редакса, непосредственно при получение ответа с сервера, а не в компоненте

//return <Redirect to='/checkout/success' />
}
if (checkOutState.error) {
history.replace('/checkout/error');
// return <Redirect to='/checkout/error' />
}
if (!total) {
return (
<div className={styles.basket}>
<h4 className={styles.title}>Select a meal from the list</h4>
</div>
);
}

const totalprice = Math.round(total * currencyValue);
return (
<div className={styles.basket}>
{/* <h4 className={styles.title}>{`${name}'s ${title}`}</h4> */}
Expand Down Expand Up @@ -52,11 +77,11 @@ function Basket({ title = 'Basket', total, orderProducts }) {
<p>Total</p>
</div>
<div className={itemStyles.info}>
<p>{`${total} $`}</p>
<p>{`${totalprice} ${currencyName}`}</p>
</div>
</div>
<Link to="/checkout">
<Button primary block>
<Button onClick={onCheckoutClickHandler} primary block>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

в этом случае проще сделать две отдельные кнопки

checkout
</Button>
</Link>
Expand Down
36 changes: 35 additions & 1 deletion src/components/header/header.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,49 @@
import React, { useContext } from 'react';
import {
activeCurrencySelector,
allCurrenciesArraySelector,
} from '../../redux/selectors';

import Logo from './logo';
import styles from './header.module.css';
import { userContext } from '../../contexts/user-context';
import { useDispatch, useSelector } from 'react-redux';
import { setCurrency } from '../../redux/actions';

const Header = () => {
const allCurrenciesEnteries = useSelector(allCurrenciesArraySelector);
const activeCurrency = useSelector(activeCurrencySelector);
const dispatch = useDispatch();

const { name, setName } = useContext(userContext);

return (
<header className={styles.header} onClick={() => setName('Ivan')}>
<Logo />
<h2>{name}</h2>
{/* <h2>{name}</h2> */}
<div className={styles.currencySwitcher}>
{allCurrenciesEnteries.map((currArr) => {
const [name, value] = currArr;
return (
<h4
className={styles.currencyItem}
key={name}
onClick={() => dispatch(setCurrency(name))}
>
{' '}
{name} : {value}{' '}
</h4>
);
})}
{Object.entries(activeCurrency).map((activeItemArr) => {
const [name, value] = activeItemArr;
return (
<h4 className={styles.currencyItemActive} key={name}>
{name} : {value}
</h4>
);
})}
</div>
</header>
);
};
Expand Down
28 changes: 28 additions & 0 deletions src/components/header/header.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,31 @@
right: 20px;
top: 0;
}
.currencySwitcher {
display: flex;
align-items: center;
justify-content: space-around;
position: absolute;
color: var(--white);
right: 20px;
top: 0;
}

.currencySwitcher :hover {
color: gold;
}

.currencySwitcherActive {
color: gold;
}
.currencySwitcher h3 {
display: inline;
margin-left: 10px;
}
.currencyItem {
margin-right: 20px;
}
.currencyItemActive {
color: gold;
font-size: larger;
}
16 changes: 13 additions & 3 deletions src/components/product/product.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,27 @@ import styles from './product.module.css';
import { decrement, increment } from '../../redux/actions';

import Button from '../button';
import { productAmountSelector, productSelector } from '../../redux/selectors';
import {
productAmountSelector,
productSelector,
activeCurrencySelector,
} from '../../redux/selectors';

const Product = ({ product, amount, increment, decrement }) => {
const Product = ({ product, amount, increment, decrement, currency }) => {
if (!product) return null;
const activeCurrency = currency;
const [currencyName, currencyValue] = Object.entries(activeCurrency)[0];
const price = Math.round(currencyValue * product.price);

return (
<div className={styles.product} data-id="product">
<div className={styles.content}>
<div>
<h4 className={styles.title}>{product.name}</h4>
<p className={styles.description}>{product.ingredients.join(', ')}</p>
<div className={styles.price}>{product.price} $</div>
<div className={styles.price}>
{price} {currencyName}
</div>
</div>
<div>
<div className={styles.counter}>
Expand Down Expand Up @@ -51,6 +60,7 @@ Product.propTypes = {
const mapStateToProps = createStructuredSelector({
amount: productAmountSelector,
product: productSelector,
currency: activeCurrencySelector,
});

const mapDispatchToProps = (dispatch, ownProps) => ({
Expand Down
2 changes: 1 addition & 1 deletion src/pages/restaurants-page.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { connect, useSelector } from 'react-redux';
import { connect } from 'react-redux';
import { Redirect, Route } from 'react-router-dom';
import { createStructuredSelector } from 'reselect';
import Restaurants from '../components/restaurants';
Expand Down
35 changes: 34 additions & 1 deletion src/redux/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,28 @@ import {
LOAD_REVIEWS,
LOAD_PRODUCTS,
LOAD_USERS,
CHECKOUT_PRODUCTS,
REQUEST,
SUCCESS,
FAILURE,
CLEAR_BASKET,
SET_CURRENCY,
} from './constants';
import {
usersLoadingSelector,
usersLoadedSelector,
reviewsLoadingSelector,
reviewsLoadedSelector,
} from './selectors';

export const increment = (id) => ({ type: INCREMENT, payload: { id } });
export const decrement = (id) => ({ type: DECREMENT, payload: { id } });
export const remove = (id) => ({ type: REMOVE, payload: { id } });
export const clearBasket = () => ({ type: CLEAR_BASKET });

export const setCurrency = (currencyName) => ({
type: SET_CURRENCY,
payload: currencyName,
});

export const addReview = (review, restaurantId) => ({
type: ADD_REVIEW,
Expand Down Expand Up @@ -63,3 +74,25 @@ export const loadUsers = () => async (dispatch, getState) => {

dispatch(_loadUsers());
};

export const checkoutProducts = (basketItems) => async (dispatch) => {
const itemsArr = basketItems.map((basketItem) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

тут так же можно использовать селектор

return { id: basketItem.product.id, amount: basketItem.amount };
});

dispatch({ type: CHECKOUT_PRODUCTS + REQUEST });

const request = await fetch('/api/order', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify([...itemsArr]),
});
const response = await request.json();
if (response !== 'ok') {
dispatch({ type: CHECKOUT_PRODUCTS + FAILURE, payload: response });
} else {
dispatch({ type: CHECKOUT_PRODUCTS + SUCCESS, payload: response });
}
};
6 changes: 6 additions & 0 deletions src/redux/constants.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const REMOVE = 'REMOVE';
export const CLEAR_BASKET = 'CLEAR_BASKET';

export const ADD_REVIEW = 'ADD_REVIEW';

export const SET_CURRENCY = 'SET_CURRENCY';

export const LOAD_RESTAURANTS = 'LOAD_RESTAURANTS';
export const LOAD_PRODUCTS = 'LOAD_PRODUCTS';
export const LOAD_REVIEWS = 'LOAD_REVIEWS';
export const LOAD_USERS = 'LOAD_USERS';

export const CHECKOUT_PRODUCTS = 'CHECKOUT_PRODUCTS';

export const REQUEST = '_REQUEST';
export const SUCCESS = '_SUCCESS';
export const FAILURE = '_FAILURE';
4 changes: 4 additions & 0 deletions src/redux/reducer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import restaurants from './restaurants';
import products from './products';
import reviews from './reviews';
import users from './users';
import checkout from './checkout';
import currency from './currency';

import history from '../../history';

Expand All @@ -16,4 +18,6 @@ export default combineReducers({
products,
reviews,
users,
checkout,
currency,
});
4 changes: 3 additions & 1 deletion src/redux/reducer/order.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DECREMENT, INCREMENT, REMOVE } from '../constants';
import { CLEAR_BASKET, DECREMENT, INCREMENT, REMOVE } from '../constants';

// { [productId]: amount }
export default (state = {}, action) => {
Expand All @@ -16,6 +16,8 @@ export default (state = {}, action) => {
...state,
[payload.id]: 0,
};
case CLEAR_BASKET:
return {};
default:
return state;
}
Expand Down
6 changes: 6 additions & 0 deletions src/redux/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ const orderSelector = (state) => state.order;
const productsSelector = (state) => state.products.entities;
const reviewsSelector = (state) => state.reviews.entities;
const usersSelector = (state) => state.users.entities;
const currenciesSelector = (state) => state.currency.entities;
export const activeCurrencySelector = (state) => state.currency.activeCurrency;

export const allCurrenciesArraySelector = createSelector(
currenciesSelector,
(currencies) => Object.entries(currencies)
);
export const restaurantsLoadingSelector = (state) => state.restaurants.loading;
export const restaurantsLoadedSelector = (state) => state.restaurants.loaded;

Expand Down