Commit a01fa831 authored by Nurasyl's avatar Nurasyl

redux

parent e438efa6
This diff is collapsed.
......@@ -9,9 +9,11 @@
"preview": "vite preview"
},
"dependencies": {
"@reduxjs/toolkit": "^2.2.5",
"axios": "^1.6.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.0"
},
"devDependencies": {
......
import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import BurgerBuilder from './containers/BurgerBuilder/BurgerBuilder';
import { Checkout } from './containers/Checkout/Checkout';
import { NotFound } from './components/NotFound/NotFound';
import { ContactData } from './containers/ContactData/ContactData';
import { Layout } from './components/Layout/Layout';
import { Orders } from './containers/Orders/Orders';
import Orders from './containers/Orders/Orders';
import { store } from './store';
function App() {
return (
<Provider store={store}>
<BrowserRouter>
<Routes>
<Route path='/' element={<Layout/>}>
......@@ -21,6 +24,7 @@ function App() {
</Route>
</Routes>
</BrowserRouter>
</Provider>
)
}
......
import { parseGetOrders } from "@/helpers/parseGetOrders";
import axios from "axios";
axios.defaults.baseURL = "https://burger-278a4-default-rtdb.firebaseio.com/";
const axiosBurger = axios;
const axiosBurger = axios.create({
baseURL: "https://burger-278a4-default-rtdb.firebaseio.com/"
});
export default axiosBurger;
\ No newline at end of file
import React, { useState } from 'react';
import { useNavigate, createSearchParams } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import type { Ingredients, IngredientNames } from '@/interfaces/Ingredients';
import Burger from '@/components/Burger/Burger';
import BuildControls from '@/components/BuildControls/BuildControls';
import { IngredientPrices } from '@/helpers/IngPrice';
import { Modal } from '@/components/UI/Modal/Modal';
import { OrderSummary } from '@/components/Burger/OrderSummary';
import { useAppSelector } from '@/store';
import { useAppDispatch } from '@/store';
import { setIngredients } from '@/store/ingredients.slice';
const BurgerBuilder = () => {
const navigate = useNavigate();
const dispatch = useAppDispatch();
const {ingredints} = useAppSelector(state => state);
const [totalPrice, setTotalPrice] = useState<number>(IngredientPrices.bread);
const [purshasable, setPurshasable] = useState<boolean>(false);
const [show, setShow] = useState<boolean>(false);
const [ingredients, setIngredients] = useState<Ingredients>({
salad: 0,
meat: 0,
bacon: 0,
cheese: 0
});
const onLessClick = (ingType: IngredientNames) => {
const ingredientsCopy = {...ingredients};
if(ingredientsCopy[ingType] > 0) {
ingredientsCopy[ingType] -= 1;
setIngredients(ingredientsCopy);
if(ingredints[ingType] > 0) {
dispatch(setIngredients({ingType, actionType: "less"}));
setTotalPrice(prevState => prevState - IngredientPrices[ingType]);
updatePurshasable(ingredientsCopy);
};
updatePurshasable(ingredints);
}
};
const onMoreClick = (ingType: IngredientNames) => {
const ingredientsCopy = {...ingredients};
ingredientsCopy[ingType] += 1;
dispatch(setIngredients({ingType, actionType: "more"}));
setTotalPrice(prevState => prevState + IngredientPrices[ingType]);
setIngredients(ingredientsCopy);
updatePurshasable(ingredientsCopy);
updatePurshasable(ingredints);
};
const updatePurshasable = (ings: Ingredients) => {
......@@ -54,31 +49,27 @@ const BurgerBuilder = () => {
};
const onPurchaseContinued = () => {
const searchParams = createSearchParams(ingredients as unknown as URLSearchParams)
navigate({
pathname: "/checkout",
search: `${searchParams.toString()}`
})
navigate({pathname: "/checkout"})
};
return (
<>
<Modal show={show} onClosed={onClosedHandler}>
<OrderSummary
ingredients={ingredients}
ingredients={ingredints}
price={totalPrice}
purchaseCancelled={onClosedHandler}
purchaseContinued={onPurchaseContinued}
/>
</Modal>
<Burger ingredients={ingredients}/>
<Burger ingredients={ingredints}/>
<BuildControls
purshasable={purshasable}
price={totalPrice}
onLessClick={onLessClick}
onMoreClick={onMoreClick}
onOpenModal={onOpenModalHandler}
ingredients={ingredients}
ingredients={ingredints}
/>
</>
)
......
import React, {useRef} from 'react';
import {useSearchParams, Outlet, useNavigate, NavLink} from "react-router-dom";
import type {IngredientNames, Ingredients} from '@/interfaces/Ingredients';
import React from 'react';
import {Outlet, useNavigate} from "react-router-dom";
import { CheckoutSummary } from '@/components/Order/CheckoutSummary/CheckoutSummary';
import { parseParams } from '@/helpers/parseParams';
import { getTotalPrice } from '@/helpers/getTotalPrice';
import { IngredientPrices } from '@/helpers/IngPrice';
import { useAppSelector } from '@/store';
export const Checkout = () => {
const navigate = useNavigate();
const [params] = useSearchParams();
const ingredients = useRef(parseParams<Ingredients>(params));
const {ingredints} = useAppSelector(state => state);
const checkoutCancelledHandler = () => {
navigate(-1);
};
const checkoutContinuedHandler = () => {
const price = getTotalPrice(ingredients.current);
navigate('contactData', {state: {ingredients: ingredients.current, price}});
navigate('contactData');
};
return (
<>
<CheckoutSummary
ingredients={ingredients.current}
ingredients={ingredints}
checkoutCancelled={checkoutCancelledHandler}
checkoutContinued={checkoutContinuedHandler}
/>
......
......@@ -2,18 +2,17 @@ import React, { useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import axiosBurger from '@/config/axiosBurger';
import { Button } from "@/components/UI/Button/Button";
import { Ingredients } from '@/interfaces/Ingredients';
import { TContactData } from '@/interfaces/contactData';
import { parseContactData } from '@/helpers/parseContactData';
import { Modal } from '@/components/UI/Modal/Modal';
import { Spinner } from '@/components/UI/Spinner/Spinner';
import { useAppSelector } from '@/store';
import './ContactData.css';
export const ContactData = () => {
const location = useLocation();
const navigate = useNavigate();
const {ingredints} = useAppSelector(state => state);
const [ingredients, setIngredients] = useState<Ingredients | null>(parseContactData(location));
const [isLoading, setIsLoading] = useState<boolean>(false);
const [showModal, setShowModal] = useState<boolean>(false);
const [contactData, setContactData] = useState<TContactData>({
......@@ -34,7 +33,7 @@ export const ContactData = () => {
const allDataReq = Object.values(contactData).every(el => el !== "");
const order = {
ingredients,
ingredints,
contactData,
price: location.state.price
};
......
......@@ -5,18 +5,16 @@ import { parseGetOrders } from "@/helpers/parseGetOrders";
import { TOrder } from "@/interfaces/order";
import { OrderItem } from "@/components/Order/OrderItem/OrderItem";
import { Spinner } from "@/components/UI/Spinner/Spinner";
import withSpinnerHandler from "@/hoc/withSpinnerHandler";
export const Orders = () => {
const Orders = () => {
const navigate = useNavigate();
const [orders, setOrders] = useState<TOrder[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(false);
const getOrders = useCallback(async () => {
setIsLoading(true);
const {data} = await axiosBurger.get("orders.json");
const {data} = await axiosBurger.get("orders");
setOrders(parseGetOrders(data).reverse());
setIsLoading(false);
}, []);
useEffect(() => {
......@@ -30,9 +28,7 @@ export const Orders = () => {
};
return (
<>
<Spinner show={isLoading}/>
{
orders.map(order => (
<OrderItem
......@@ -46,3 +42,6 @@ export const Orders = () => {
</>
);
};
export default withSpinnerHandler(Orders, axiosBurger)
\ No newline at end of file
import React, { useState, FunctionComponent, useEffect } from 'react';
import { AxiosInstance, AxiosResponse, AxiosError } from 'axios';
import { Modal } from '@/components/UI/Modal/Modal';
const withSpinnerHandler = <T extends object>(WrappedComponent: FunctionComponent<T>, axios: AxiosInstance) => {
return (props: T) => {
const [error, setError] = useState<string>("");
const [show, setShow] = useState<boolean>(false)
const succesHandler = async (res: AxiosResponse<any, any>) => {
return res
};
const rejectHandler = (rej: AxiosError<any, any>) => {
setError(rej.message)
setShow(true)
return rej
};
const onClosedHandler = () => {
setShow(false)
};
useEffect(() => {
axios.interceptors.response.use(succesHandler, rejectHandler);
}, []);
return (
<>
<Modal show={show} onClosed={onClosedHandler}>
<h1>{error}</h1>
</Modal>
<WrappedComponent {...props} />
</>
);
};
};
export default withSpinnerHandler;
\ No newline at end of file
import { configureStore } from "@reduxjs/toolkit";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { ingredientsSlice } from "./ingredients.slice";
export const store = configureStore({
reducer: {
ingredints: ingredientsSlice.reducer
}
});
type RootState = ReturnType<typeof store.getState>;
type AppDispatch = typeof store.dispatch;
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
\ No newline at end of file
import { createSlice } from "@reduxjs/toolkit";
import { IngredientNames, Ingredients } from "@/interfaces/Ingredients";
const initialState: Ingredients = {
salad: 0,
meat: 0,
bacon: 0,
cheese: 0
};
export const ingredientsSlice = createSlice({
name: "ingredients",
initialState,
reducers: {
setIngredients(state, action) {
const {ingType, actionType} = action.payload as {ingType: IngredientNames, actionType: string}
if(actionType === "more") {
state[ingType] += 1
} else if(actionType === "less") {
if(state[ingType] > 0) {
state[ingType] -= 1
}
}
}
}
});
export const {setIngredients} = ingredientsSlice.actions;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment