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 all commits
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
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,26 @@
5. При загрузках показывать лоадеры, все грузить максимально низко, там где эти данные нужны
6. Все данные грузить только один раз (не загружать повторно данные, которые уже есть)
7. (Опционально) переписать все на **immer**

# HT6

<<<<<<< HEAD

1. Сделать reviews/menu отдельными роутами (/restaurant/:id/reviews)
2. # В корзине сделать продукты линками на их ресторан
3. Сделать reviews/menu отдельными роутами (/restaurants/:id/reviews)
4. В корзине сделать продукты линками на их ресторан

## HT7

1. Сделать редирект со **/** и с **/restaurants** на страницу ресторана
2. Проверить если мы на **/checkout**, то при нажатии на кнопку:

- отправить **POST** запрос на: '/api/order' с **JSON** формата [{id: "d75f762a-eadd-49be-8918-ed0daa8dd024", amount: 2}]
- блокировать кнопку на время запроса (можно добавить лоадер)
- при успешном ответе (при сумме заказа от 50 до 200) редиректить на новую страницу "Спасибо за заказ!" и очищать корзину
- при ошибке редиректить на странцу ошибки, показать текст ошибки

3. Реализовать переключение валюты, хранить словарь словарь в контексте (минимум 3 валюты)
4. Анимировать добавление ревью использус css modules
> > > > > > > 166edbb61a24a152c0ff97469b26dfa82afad873
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@wojtekmaj/enzyme-adapter-react-17": "^0.4.1",
"classnames": "^2.2.6",
"concurrently": "^5.3.0",
"connected-react-router": "^6.8.0",
"enzyme": "^3.11.0",
"immer": "^8.0.0",
"normalize.css": "^8.0.1",
Expand All @@ -19,6 +20,7 @@
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.1",
"react-transition-group": "^4.4.1",
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.8",
"redux-thunk": "^2.3.0",
Expand Down
17 changes: 17 additions & 0 deletions simple_api/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,21 @@ router.get('/users', (req, res, next) => {
reply(res, users);
});

const min = (m) => `you ordered for $${m}, but the min order amount is $50`;
const max = (m) => `you ordered for $${m}, but the max order amount is $200`;

router.post('/order', function (req, res, next) {
try {
const total = req.body
.map((it) => products.find((p) => p.id === it.id).price * it.amount)
.reduce((acc, next) => acc + next, 0);

if (total < 50) return reply(res, min(total), 3000, 400);
if (total > 200) return reply(res, max(total), 3000, 400);
return reply(res, 'ok', 3000);
} catch {
return reply(res, 'wrong data', 1000, 400);
}
});

module.exports = router;
38 changes: 26 additions & 12 deletions src/components/app/app.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
import React, { PureComponent } from 'react';
import { Route, Switch } from 'react-router-dom';
import React, { useState } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
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';

export default class App extends PureComponent {
render() {
return (
<div>
const App = () => {
const [name, setName] = useState('Igor');

return (
<div>
<UserProvider value={{ name, setName }}>
<Header />
<Switch>
<Route path="/" exact component={() => 'Main page'} />
<Route path="/checkout/error" component={CheckOutFail} />
<Route path="/checkout/success" component={CheckOutSuccess} />
<Route path="/checkout" component={Basket} />
<Route path="/restaurants" component={RestaurantsPage} />
<Route path="/" component={() => '404 - Not found'} />
<Route path="/error" component={() => <h1>Error Page</h1>} />
<Route
path="/"
component={() => {
return <Redirect to="/restaurants" />;
}}
/>
</Switch>
</div>
);
}
}
</UserProvider>
</div>
);
};

export default App;
16 changes: 13 additions & 3 deletions src/components/basket/basket-item/basket-item.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,40 @@
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,
amount,
subtotal,
restaurantId,
increment,
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}>
<span>{product.name}</span>
<Link to={`/restaurants/${restaurantId}/menu`}>
<span>{product.name}</span>
</Link>
</div>
<div className={styles.info}>
<div className={styles.counter}>
<Button onClick={decrement} icon="minus" secondary small />
<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
20 changes: 20 additions & 0 deletions src/components/basket/basket.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.basket-animation-enter {
opacity: 0;
transform: scale(0.9);
}

.basket-animation-enter-active {
opacity: 1;
transform: translateX(0);
transition: opacity 300ms, transform 300ms;
}

.basket-animation-exit {
opacity: 1;
}

.basket-animation-exit-active {
opacity: 0;
transform: scale(0.9);
transition: opacity 300ms, transform 300ms;
}
72 changes: 57 additions & 15 deletions src/components/basket/basket.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,87 @@
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 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}>{title}</h4>
{orderProducts.map(({ product, amount, subtotal }) => (
<BasketItem
product={product}
amount={amount}
key={product.id}
subtotal={subtotal}
/>
))}
{/* <h4 className={styles.title}>{`${name}'s ${title}`}</h4> */}
<h4 className={styles.title}>
<UserConsumer>{({ name }) => `${name}'s ${title}`}</UserConsumer>
</h4>
<TransitionGroup>
{orderProducts.map(({ product, amount, subtotal, restaurantId }) => (
<CSSTransition
key={product.id}
timeout={10000}
classNames="basket-animation"
>
<BasketItem
product={product}
amount={amount}
subtotal={subtotal}
restaurantId={restaurantId}
/>
</CSSTransition>
))}
</TransitionGroup>
<hr className={styles.hr} />
<div className={itemStyles.basketItem}>
<div className={itemStyles.name}>
<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
51 changes: 45 additions & 6 deletions src/components/header/header.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,51 @@
import React from 'react';
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 = () => (
<header className={styles.header}>
<Logo />
</header>
);
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> */}
<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>
);
};

export default Header;
36 changes: 36 additions & 0 deletions src/components/header/header.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,40 @@
justify-content: center;
height: 60px;
background: var(--black);
position: relative;
}

.header h2 {
position: absolute;
color: var(--white);
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;
}
Loading