Skip to content

Commit

Permalink
HW-7 Send order
Browse files Browse the repository at this point in the history
  • Loading branch information
vera-l committed Dec 24, 2021
1 parent 46ef421 commit eab5cc5
Show file tree
Hide file tree
Showing 14 changed files with 159 additions and 27 deletions.
9 changes: 8 additions & 1 deletion src/components/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Header from '../header';
import Basket from '../basket';
import { UserProvider } from '../../contexts/user-context';
import { useState } from 'react';
import Success from '../success';
import Error from '../error';

const App = () => {
const [name, setName] = useState('Andrey');
Expand All @@ -15,7 +17,12 @@ const App = () => {
<Redirect exact from="/" to="/restaurants" />
<Route path="/checkout" component={Basket} />
<Route path="/restaurants" component={Restaurants} />
<Route path="/error" component={() => <h2>Error Page!</h2>} />
<Route path="/success">
<Success>Your order has been sent</Success>
</Route>
<Route path="/error">
<Error>Error Page!</Error>
</Route>
<Route path="/" component={() => <h2>404 - Page Not Found :(</h2>} />
</Switch>
</UserProvider>
Expand Down
48 changes: 37 additions & 11 deletions src/components/basket/basket.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { Link, Switch, Route } from 'react-router-dom';
import { CSSTransition, TransitionGroup } from 'react-transition-group';

import styles from './basket.module.css';
import './basket.css';
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 {
orderProductsSelector,
totalSelector,
orderSendingLoadingSelector,
} from '../../redux/selectors';
import { UserConsumer } from '../../contexts/user-context';
import ConvertedValue from '../converted-value/converted-value';
import { sendOrder } from '../../redux/actions';

function Basket({ title = 'Basket', total, orderProducts }) {
// const { name } = useContext(userContext);

function Basket({
title = 'Basket',
total,
orderProducts,
sendOrder,
loading,
loaded,
}) {
if (!total) {
return (
<div className={styles.basket}>
Expand Down Expand Up @@ -55,11 +65,26 @@ function Basket({ title = 'Basket', total, orderProducts }) {
</p>
</div>
</div>
<Link to="/checkout">
<Button primary block>
checkout
</Button>
</Link>
<Switch>
<Route path="/checkout">
{!loading ? (
<Button primary block onClick={sendOrder}>
send
</Button>
) : (
<Button disabled primary block onClick={null}>
send
</Button>
)}
</Route>
<Route>
<Link to="/checkout">
<Button primary block>
checkout
</Button>
</Link>
</Route>
</Switch>
</div>
);
}
Expand All @@ -68,7 +93,8 @@ const mapStateToProps = (state) => {
return {
total: totalSelector(state),
orderProducts: orderProductsSelector(state),
loading: orderSendingLoadingSelector(state),
};
};

export default connect(mapStateToProps)(Basket);
export default connect(mapStateToProps, { sendOrder })(Basket);
4 changes: 4 additions & 0 deletions src/components/button/button.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,7 @@
padding: 11px 20px;
height: 50px;
}

.button[disabled] {
background: #777;
}
7 changes: 7 additions & 0 deletions src/components/error/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styles from './error.module.css';

function Error({ children }) {
return <div className={styles.error}>{children}</div>;
}

export default Error;
4 changes: 4 additions & 0 deletions src/components/error/error.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.error {
padding: 20px 10px;
color: #f00;
}
1 change: 1 addition & 0 deletions src/components/error/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './error';
1 change: 1 addition & 0 deletions src/components/success/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './success';
7 changes: 7 additions & 0 deletions src/components/success/success.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styles from './success.module.css';

function Success({ children }) {
return <div className={styles.success}>{children}</div>;
}

export default Success;
4 changes: 4 additions & 0 deletions src/components/success/success.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.success {
padding: 20px 10px;
color: #0f0;
}
21 changes: 20 additions & 1 deletion src/redux/actions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { replace } from 'connected-react-router';
import { replace, push } from 'connected-react-router';
import {
DECREMENT,
INCREMENT,
Expand All @@ -12,13 +12,15 @@ import {
REQUEST,
SUCCESS,
FAILURE,
SEND_ORDER,
} from './constants';

import {
usersLoadingSelector,
usersLoadedSelector,
reviewsLoadingSelector,
reviewsLoadedSelector,
orderDataSelector,
} from './selectors';

export const increment = (id) => ({ type: INCREMENT, id });
Expand Down Expand Up @@ -77,3 +79,20 @@ export const loadUsers = () => async (dispatch, getState) => {

dispatch(_loadUsers());
};

export const sendOrder = () => async (dispatch, getState) => {
const state = getState();
const orderData = orderDataSelector(state);

try {
await dispatch({
type: SEND_ORDER,
CallAPI: '/api/order',
method: 'POST',
body: orderData,
});
dispatch(push('/success'));
} catch {
dispatch(push('/error'));
}
};
1 change: 1 addition & 0 deletions src/redux/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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 SEND_ORDER = 'SEND_ORDER';

export const REQUEST = '_REQUEST';
export const SUCCESS = '_SUCCESS';
Expand Down
15 changes: 11 additions & 4 deletions src/redux/middleware/api.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import { FAILURE, REQUEST, SUCCESS } from '../constants';

const DEFAULT_METHOD = 'GET';

export default (store) => (next) => async (action) => {
if (!action.CallAPI) return next(action);

const { CallAPI, type, ...rest } = action;
const { CallAPI, type, method, body, ...rest } = action;

next({ ...rest, type: type + REQUEST });

try {
const data = await fetch(CallAPI).then((res) => res.json());
const response = await fetch(CallAPI, {
method: method || DEFAULT_METHOD,
body: JSON.stringify(body) || null,
headers: { 'Content-Type': 'application/json' },
});
const data = await response.json();
if (!response.ok) throw data;
next({ ...rest, type: type + SUCCESS, data });
} catch (error) {
next({ ...rest, type: type + FAILURE, error });
throw next({ ...rest, type: type + FAILURE, error });
}
};
56 changes: 47 additions & 9 deletions src/redux/reducer/order.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,54 @@
import { DECREMENT, INCREMENT, REMOVE } from '../constants';
import produce from 'immer';

import {
DECREMENT,
INCREMENT,
REMOVE,
SEND_ORDER,
REQUEST,
SUCCESS,
FAILURE,
} from '../constants';

const initialState = {
entities: {},
loading: false,
loaded: false,
error: null,
};

export default produce((draft = initialState, action) => {
const { type, id, error } = action;

// { [productId]: amount }
export default function (state = {}, action) {
const { type, id } = action;
switch (type) {
case INCREMENT:
return { ...state, [id]: (state[id] || 0) + 1 };
draft.entities[id] = (draft.entities[id] || 0) + 1;
break;

case DECREMENT:
return { ...state, [id]: state[id] > 0 ? (state[id] || 0) - 1 : 0 };
draft.entities[id] =
draft.entities[id] > 0 ? (draft.entities[id] || 0) - 1 : 0;
break;

case REMOVE:
return { ...state, [id]: 0 };
draft.entities[id] = 0;
break;

case SEND_ORDER + REQUEST: {
draft.loading = true;
break;
}
case SEND_ORDER + SUCCESS: {
draft.loading = false;
draft.entities = {};
break;
}
case SEND_ORDER + FAILURE: {
draft.loading = false;
draft.error = error;
break;
}
default:
return state;
return draft;
}
}
});
8 changes: 7 additions & 1 deletion src/redux/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createSelector } from 'reselect';

const restaurantsSelector = (state) => state.restaurants.entities;
const productsSelector = (state) => state.products.entities;
const orderSelector = (state) => state.order;
const orderSelector = (state) => state.order.entities;
const reviewsSelector = (state) => state.reviews.entities;
const usersSelector = (state) => state.users.entities;

Expand Down Expand Up @@ -34,6 +34,8 @@ export const productSelector = (state, { id }) => productsSelector(state)[id];
export const reviewSelector = (state, { id }) => reviewsSelector(state)[id];
export const amountSelector = (state, { id }) => orderSelector(state)[id] || 0;

export const orderSendingLoadingSelector = (state) => state.order.loading;

const restaurantsIdsByProductsSelector = createSelector(
restaurantsListSelector,
(restaurants) =>
Expand Down Expand Up @@ -86,3 +88,7 @@ export const averageRatingSelector = createSelector(
);
}
);

export const orderDataSelector = createSelector(orderSelector, (order) =>
Object.entries(order).map(([id, amount]) => ({ id, amount }))
);

0 comments on commit eab5cc5

Please sign in to comment.