- {amount}
+
);
};
diff --git a/src/contexts/currency-context.js b/src/contexts/currency-context.js
new file mode 100644
index 0000000..4156bb0
--- /dev/null
+++ b/src/contexts/currency-context.js
@@ -0,0 +1,27 @@
+import { createContext } from 'react';
+
+export const currDictionary = {
+ ruble: {
+ name: 'руб.',
+ rateToDollar: 70,
+ },
+ dollar: {
+ name: '$',
+ rateToDollar: 1,
+ },
+ euro: {
+ name: 'eur.',
+ rateToDollar: 0.8,
+ },
+};
+
+export const getMoneyInCurr = (value, curr, currDictionary) => {
+ const countedVal = value * currDictionary[curr].rateToDollar;
+ const roundedVal = parseInt(countedVal * 100) / 100;
+ return `${roundedVal} ${currDictionary[curr].name}`;
+};
+
+export const currencyContext = createContext();
+
+export const CurrencyProvider = currencyContext.Provider;
+export const CurrencyConsumer = currencyContext.Consumer;
diff --git a/src/redux/actions.js b/src/redux/actions.js
index ef07010..67c863b 100644
--- a/src/redux/actions.js
+++ b/src/redux/actions.js
@@ -1,4 +1,4 @@
-import { replace } from 'connected-react-router';
+import { push, replace } from 'connected-react-router';
import {
DECREMENT,
INCREMENT,
@@ -12,6 +12,7 @@ import {
REQUEST,
SUCCESS,
FAILURE,
+ CHECKOUT,
} from './constants';
import {
@@ -19,6 +20,8 @@ import {
usersLoadedSelector,
reviewsLoadingSelector,
reviewsLoadedSelector,
+ orderToCheckoutSelector,
+ routePathSelector,
} from './selectors';
export const increment = (id) => ({ type: INCREMENT, id });
@@ -77,3 +80,40 @@ export const loadUsers = () => async (dispatch, getState) => {
dispatch(_loadUsers());
};
+
+export const checkoutOrder = () => async (dispatch, getState) => {
+ const state = getState();
+ const path = routePathSelector(state);
+
+ switch (path) {
+ case '/checkout':
+ {
+ dispatch({ type: CHECKOUT + REQUEST });
+ const order = orderToCheckoutSelector(state);
+ try {
+ const response = await fetch('/api/order', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(order),
+ });
+
+ const status = response.status;
+ if (status === 200) {
+ dispatch({ type: CHECKOUT + SUCCESS });
+ dispatch(push('/orser-success'));
+ } else {
+ const error = await response.json();
+ dispatch({ type: CHECKOUT + FAILURE, error });
+ dispatch(push('/orser-failed', error));
+ }
+ } catch (error) {
+ dispatch({ type: CHECKOUT + FAILURE, error });
+ dispatch(push('/error'));
+ }
+ }
+ break;
+ default:
+ dispatch(push('/checkout'));
+ break;
+ }
+};
diff --git a/src/redux/constants.js b/src/redux/constants.js
index 6429975..8354542 100644
--- a/src/redux/constants.js
+++ b/src/redux/constants.js
@@ -1,6 +1,7 @@
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const REMOVE = 'REMOVE';
+
export const ADD_REVIEW = 'ADD_REVIEW';
export const CHANGE_RESTAURANT = 'CHANGE_RESTAURANT';
@@ -9,6 +10,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 CHECKOUT = 'CHECKOUT';
export const REQUEST = '_REQUEST';
export const SUCCESS = '_SUCCESS';
diff --git a/src/redux/reducer/order.js b/src/redux/reducer/order.js
index e20530c..00a4e2f 100644
--- a/src/redux/reducer/order.js
+++ b/src/redux/reducer/order.js
@@ -1,16 +1,51 @@
-import { DECREMENT, INCREMENT, REMOVE } from '../constants';
+import produce from 'immer';
+import {
+ DECREMENT,
+ INCREMENT,
+ REMOVE,
+ CHECKOUT,
+ REQUEST,
+ SUCCESS,
+ FAILURE,
+} from '../constants';
+
+const initialState = {
+ sending: false,
+ sended: false,
+ entities: {},
+ error: null,
+};
// { [productId]: amount }
-export default function (state = {}, action) {
- const { type, id } = action;
+export default produce((draft = initialState, action) => {
+ const { type, id, error } = 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 CHECKOUT + REQUEST: {
+ draft.error = null;
+ draft.sending = true;
+ break;
+ }
+ case CHECKOUT + SUCCESS: {
+ draft.sending = false;
+ draft.entities = {};
+ break;
+ }
+ case CHECKOUT + FAILURE: {
+ draft.sending = false;
+ draft.error = error;
+ break;
+ }
default:
- return state;
+ return draft;
}
-}
+});
diff --git a/src/redux/selectors.js b/src/redux/selectors.js
index 94b62a0..9e044ca 100644
--- a/src/redux/selectors.js
+++ b/src/redux/selectors.js
@@ -2,9 +2,10 @@ 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;
+const routeLocationSelector = (state) => state.router.location;
export const activeIdRestaurantSelector = (state) => state.restaurants.activeId;
export const restaurantsLoadingSelector = (state) => state.restaurants.loading;
@@ -88,3 +89,16 @@ export const averageRatingSelector = createSelector(
);
}
);
+
+export const orderToCheckoutSelector = createSelector(orderSelector, (order) =>
+ Object.entries(order).reduce(
+ (acc, [id, amount]) => [...acc, { id, amount }],
+ []
+ )
+);
+
+export const routePathSelector = (state) =>
+ routeLocationSelector(state).pathname;
+
+export const chechoutSendingSelector = (state) => state.order.sending;
+export const chechoutErrorSelector = (state) => state.order.error;