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

Ht6 #63

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

Ht6 #63

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

## HT6

1. Сделать reviews/menu отдельными роутами (**/restaurants/:id/reviews**)
2. Сделать редиректы со **/** и с **/restaurants/:id** на страницу ресторана с меню
3. В корзине сделать продукты линками на их ресторан
39,126 changes: 39,126 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.6",
"react-router-dom": "5",
"react-scripts": "4.0.3",
"redux": "^4.1.2",
"redux-devtools-extension": "^2.13.9",
Expand Down Expand Up @@ -57,4 +58,4 @@
"prettier": "^2.5.0",
"pretty-quick": "^3.1.2"
}
}
}
9 changes: 8 additions & 1 deletion src/components/app/app.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import { PureComponent } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import Restaurants from '../restaurants';
import Header from '../header';
import Basket from '../basket';

export default class App extends PureComponent {
render() {
return (
<div>
<Header />
<Restaurants />
<Switch>
<Route path="/" exact component={Restaurants} />
Copy link
Owner

Choose a reason for hiding this comment

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

тут нужно сделать Redirect, вместо Route

<Route path="/checkout" component={Basket} />
<Route path="/restaurants" component={Restaurants} />
<Route path="/" component={() => <h2>404 - Page Not Found :(</h2>} />
</Switch>
</div>
);
}
Expand Down
36 changes: 22 additions & 14 deletions src/components/basket/basket-item/basket-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import cn from 'classnames';
import { increment, decrement, remove } from '../../../redux/actions';
import Button from '../../button';
import styles from './basket-item.module.css';
import { Link } from 'react-router-dom';
import { RestaurantOfProductSelector } from '../../../redux/selectors';

function BasketItem({
product,
Expand All @@ -11,22 +13,25 @@ function BasketItem({
increment,
decrement,
remove,
}) {
})
{
return (
<div className={styles.basketItem}>
<div className={styles.name}>
<span>{product.name}</span>
</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 />
<Link to={`/`}>
<div className={styles.basketItem}>
<div className={styles.name}>
<span>{product.name}</span>
</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>
<Button onClick={remove} icon="delete" secondary small />
</div>
<p className={cn(styles.count, styles.price)}>{subtotal} $</p>
<Button onClick={remove} icon="delete" secondary small />
</div>
</div>
</Link>
);
}

Expand All @@ -35,5 +40,8 @@ const mapDispatchToProps = (dispatch, ownProps) => ({
decrement: () => dispatch(decrement(ownProps.product.id)),
remove: () => dispatch(remove(ownProps.product.id)),
});
const mapStateToProps = (state, {id}) => ({
restaurant: RestaurantOfProductSelector(state, {id}),
});

export default connect(null, mapDispatchToProps)(BasketItem);
export default connect(mapStateToProps, mapDispatchToProps)(BasketItem);
10 changes: 7 additions & 3 deletions src/components/basket/basket.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';

import styles from './basket.module.css';
import itemStyles from './basket-item/basket-item.module.css';
Expand All @@ -20,6 +21,7 @@ function Basket({ title = 'Basket', total, orderProducts }) {
<h4 className={styles.title}>{title}</h4>
{orderProducts.map(({ product, amount, subtotal }) => (
<BasketItem
id={product.id}
product={product}
amount={amount}
key={product.id}
Expand All @@ -35,9 +37,11 @@ function Basket({ title = 'Basket', total, orderProducts }) {
<p>{`${total} $`}</p>
</div>
</div>
<Button primary block>
checkout
</Button>
<Link to="/checkout">
<Button primary block>
checkout
</Button>
</Link>
</div>
);
}
Expand Down
5 changes: 4 additions & 1 deletion src/components/header/header.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Link } from 'react-router-dom';
import { ReactComponent as Logo } from '../../icons/logo.svg';
import styles from './header.module.css';

const Header = () => (
<header className={styles.header}>
<Logo />
<Link to="/restaurants">
<Logo />
</Link>
</header>
);

Expand Down
42 changes: 39 additions & 3 deletions src/components/menu/menu.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import { loadProducts } from '../../redux/actions';
import {
productsLoadingSelector,
productsLoadedSelector,
} from '../../redux/selectors';

import Loader from '../loader';
import Product from '../product';
import Basket from '../basket';

Expand All @@ -13,14 +21,35 @@ class Menu extends Component {

state = { error: null };

loadProductsIfNeeded = () => {
const { loadProducts, restId, loading, loaded } = this.props;
if (!loading && !loaded) {
loadProducts(restId);
}
};

componentDidMount() {
this.loadProductsIfNeeded();
}

componentDidUpdate(prevProps, prevState) {
if (prevProps.restId !== this.props.restId) {
this.loadProductsIfNeeded();
}
}

componentDidCatch(error) {
this.setState({ error });
}

render() {
const { menu } = this.props;
const { menu, loading, loaded } = this.props;

if (loading) {
return <Loader />;
}

if (this.state.error) {
if (this.state.error || !loaded) {
return <p>Меню этого ресторана сейчас недоступно :(</p>;
}

Expand All @@ -39,4 +68,11 @@ class Menu extends Component {
}
}

export default Menu;
const mapStateToProps = (state, props) => ({
loading: productsLoadingSelector(state, props),
loaded: productsLoadedSelector(state, props),
});

const mapDispatchToProps = { loadProducts };

export default connect(mapStateToProps, mapDispatchToProps)(Menu);
14 changes: 2 additions & 12 deletions src/components/product/product.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useEffect } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

Expand All @@ -7,11 +6,7 @@ import Button from '../button';
import { decrement, increment } from '../../redux/actions';
import { amountSelector, productSelector } from '../../redux/selectors';

function Product({ product, amount, decrement, increment, fetchData }) {
useEffect(() => {
fetchData?.(product.id);
}, []); // eslint-disable-line

function Product({ product, amount, decrement, increment }) {
return (
<div className={styles.product} data-id="product">
<div className={styles.content}>
Expand Down Expand Up @@ -50,7 +45,7 @@ Product.propTypes = {
price: PropTypes.number,
ingredients: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
}).isRequired,
fetchData: PropTypes.func,

// from connect
amount: PropTypes.number,
decrement: PropTypes.func,
Expand All @@ -62,11 +57,6 @@ const mapStateToProps = (state, props) => ({
product: productSelector(state, props),
});

// const mapDispatchToProps = {
// decrement,
// increment,
// };

const mapDispatchToProps = (dispatch, props) => ({
decrement: () => dispatch(decrement(props.id)),
increment: () => dispatch(increment(props.id)),
Expand Down
1 change: 1 addition & 0 deletions src/components/rate/rate.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const Rate = ({ value, onChange }) => (
data-id={i <= value - 1 ? 'full-star' : 'empty-star'}
className={cn(styles.star, {
[styles.checked]: i <= value - 1,
[styles.unknown]: value === 0,
[styles.clickable]: !!onChange,
})}
onClick={onChange ? () => onChange(i + 1) : undefined}
Expand Down
4 changes: 4 additions & 0 deletions src/components/rate/rate.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
fill: var(--yellow);
}

.unknown {
fill: transparent;
}

.clickable {
cursor: pointer;
}
28 changes: 24 additions & 4 deletions src/components/restaurant/restaurant.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import Menu from '../menu';
import Reviews from '../reviews';
import Banner from '../banner';
import Rate from '../rate';
import Tabs from '../tabs';
import { NavLink, Switch, Route, Redirect } from 'react-router-dom';
import {
averageRatingSelector,
restaurantSelector,
} from '../../redux/selectors';
import styles from './restaurant.module.css';

const Restaurant = ({ restaurant, averageRating }) => {
const { id, name, menu, reviews } = restaurant;
Expand All @@ -26,9 +27,28 @@ const Restaurant = ({ restaurant, averageRating }) => {
<Banner heading={name}>
<Rate value={averageRating} />
</Banner>
<Tabs tabs={tabs} activeId={activeTab} onChange={setActiveTab} />
{activeTab === 'menu' && <Menu menu={menu} key={id} />}
{activeTab === 'reviews' && <Reviews reviews={reviews} restId={id} />}
<div className={styles.tabs}>
{tabs.map(({ id, label }) => (
<NavLink
key={id}
to={`/restaurants/${restaurant.id}/${id}`}
className={styles.tab}
activeClassName={styles.active}
onClick={() => setActiveTab(id)}
>
{label}
</NavLink>
))}
</div>
<Switch>
<Route path="/restaurants/:restId/menu">
{() => <Menu restId={id} menu={menu} />}
</Route>
<Route path="/restaurants/:restId/reviews">
{() => <Reviews restId={id} reviews={reviews} />}
</Route>
<Redirect to={`/restaurants/${id}/${activeTab}`} />
</Switch>
</div>
);
};
Expand Down
19 changes: 19 additions & 0 deletions src/components/restaurant/restaurant.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.tabs {
height: auto;
text-align: center;
padding: 12px;
background-color: var(--grey);
}

.tabs span {
cursor: pointer;
}

.tab {
padding: 4px 12px;
color: var(--black);
}

.tab.active {
border-bottom: 1px solid var(--black);
}
Loading