diff --git a/frontend/components/OrderList.js b/frontend/components/OrderList.js index 548c197..67e7a82 100644 --- a/frontend/components/OrderList.js +++ b/frontend/components/OrderList.js @@ -1,35 +1,51 @@ -import React from 'react' +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useGetOrdersQuery } from '../state/ordersApi'; +import { toggleSizeFilter } from '../state/ordersSlice'; export default function OrderList() { - const orders = [] + const { data: orders, isLoading: ordersLoading, isFetching: ordersRefreshing, error } = useGetOrdersQuery(); + + const filterSize = useSelector(state => state.ordersState.filterSize); + const dispatch = useDispatch(); + + const handleSizeFilterChange = (size) => { + dispatch(toggleSizeFilter(size)); + }; + return (
-

Pizza Orders

+

Pizza Orders {(ordersLoading || ordersRefreshing) && 'loading...'}

    { - orders.map(() => { - return ( -
  1. -
    - order details here -
    -
  2. - ) - }) + ordersLoading ? 'loading...' : + orders?.filter(order => filterSize === 'All' || order.size === filterSize) + .map(order => ( +
  3. +
    +
    {order.customer} ordered a size {order.size} with {order.toppings?.length > 0 ? `${order.toppings.length} toppings` : 'no toppings'}
    +
    +
  4. + )) }
Filter by size: { ['All', 'S', 'M', 'L'].map(size => { - const className = `button-filter${size === 'All' ? ' active' : ''}` - return + const className = `button-filter${size === 'All' ? ' active' : ''}`; + return ( + + ); }) }
- ) + ); } diff --git a/frontend/components/PizzaForm.js b/frontend/components/PizzaForm.js index 39f0509..5b6fc68 100644 --- a/frontend/components/PizzaForm.js +++ b/frontend/components/PizzaForm.js @@ -1,22 +1,83 @@ -import React from 'react' +import React, { useReducer, useState } from 'react'; +import { useCreateOrderMutation } from '../state/ordersApi'; -const initialFormState = { // suggested +const CHANGE_INPUT = 'CHANGE_INPUT'; +const TOGGLE_TOPPING = 'TOGGLE_TOPPING'; +const RESET_FORM = 'RESET_FORM'; + +const initialFormState = { fullName: '', size: '', - '1': false, - '2': false, - '3': false, - '4': false, - '5': false, -} + toppings: [], +}; + +const reducer = (state, action) => { + switch (action.type) { + case CHANGE_INPUT: { + const { name, value } = action.payload; + return { ...state, [name]: value }; + } + case TOGGLE_TOPPING: { + const { topping } = action.payload; + const newToppings = state.toppings.includes(topping) + ? state.toppings.filter(t => t !== topping) + : [...state.toppings, topping]; + return { ...state, toppings: newToppings }; + } + case RESET_FORM: + return initialFormState; + default: + return state; + } +}; export default function PizzaForm() { + const [state, dispatch] = useReducer(reducer, initialFormState); + const [error, setError] = useState(''); + const [createOrder, { isLoading: creatingOrder }] = useCreateOrderMutation(); + + const onChange = ({ target: { name, value } }) => { + dispatch({ type: CHANGE_INPUT, payload: { name, value } }); + setError(''); + }; + + const onToppingChange = ({ target: { name } }) => { + dispatch({ type: TOGGLE_TOPPING, payload: { topping: name } }); + }; + + const resetForm = () => { + dispatch({ type: RESET_FORM }); + setError(''); + }; + + const handleSubmit = (evt) => { + evt.preventDefault(); + const { fullName, size, toppings } = state; + + if (!fullName) { + setError('fullName is required'); + return; + } + if (!['S', 'M', 'L'].includes(size)) { + setError('Size must be one of the following values: S, M, L'); + return; + } + + createOrder({ fullName, size, toppings }) + .unwrap() + .then(() => { + resetForm(); + }) + .catch((err) => { + setError('Order failed: ' + err.message); + }); + }; + return ( -
+

Pizza Form

- {true &&
Order in progress...
} - {true &&
Order failed: fullName is required
} - + {creatingOrder &&
Order in progress...
} + {error &&
{error}
}

@@ -26,14 +87,21 @@ export default function PizzaForm() { name="fullName" placeholder="Type full name" type="text" + value={state.fullName} + onChange={onChange} />
-

- @@ -41,25 +109,63 @@ export default function PizzaForm() {
-
+ + Pepperoni
+ + + Green Peppers
+ + + Pineapple
+ + + Mushrooms
+ + + Ham
+
- +
- ) + ); } diff --git a/frontend/state/ordersApi.js b/frontend/state/ordersApi.js new file mode 100644 index 0000000..b1c945f --- /dev/null +++ b/frontend/state/ordersApi.js @@ -0,0 +1,27 @@ +import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; + +export const ordersApi = createApi({ + reducerPath: 'ordersApi', + baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:9009/api/pizza/' }), + tagTypes: ['Orders'], + endpoints: (builder) => ({ + getOrders: builder.query({ + query: () => 'history', + transformResponse: (response) => { + console.log('Fetched Orders:', response); + return response; + }, + providesTags: ['Orders'], + }), + createOrder: builder.mutation({ + query: (order) => ({ + url: 'order', + method: 'POST', + body: order, + }), + invalidatesTags: ['Orders'], + }), + }), +}); + +export const { useGetOrdersQuery, useCreateOrderMutation} = ordersApi; diff --git a/frontend/state/ordersSlice.js b/frontend/state/ordersSlice.js new file mode 100644 index 0000000..33c7eee --- /dev/null +++ b/frontend/state/ordersSlice.js @@ -0,0 +1,25 @@ +import { createSlice } from "@reduxjs/toolkit"; + +export const ordersSlice = createSlice({ + name: 'orders', + initialState: { + showAllOrders: true, + orderList: [], + filterSize: 'All', + }, + reducers: { + toggleShowAllOrders: state => { + state.showAllOrders = !state.showAllOrders; + }, + setOrders: (state, action) => { + state.orderList = action.payload; + }, + toggleSizeFilter: (state, action) => { + state.filterSize = action.payload; + }, + }, +}); + +export const { toggleShowAllOrders, setOrders, toggleSizeFilter } = ordersSlice.actions; + +export default ordersSlice.reducer; diff --git a/frontend/state/store.js b/frontend/state/store.js index bc9b754..98094fa 100644 --- a/frontend/state/store.js +++ b/frontend/state/store.js @@ -1,17 +1,15 @@ import { configureStore } from '@reduxjs/toolkit' +import ordersReducer from './ordersSlice'; +import { ordersApi } from './ordersApi'; -const exampleReducer = (state = { count: 0 }) => { - return state -} export const resetStore = () => configureStore({ reducer: { - example: exampleReducer, - // add your reducer(s) here + ordersState: ordersReducer, + [ordersApi.reducerPath]: ordersApi.reducer, }, middleware: getDefault => getDefault().concat( - // if using RTK Query for your networking: add your middleware here - // if using Redux Thunk for your networking: you can ignore this + ordersApi.middleware, ), }) diff --git a/package-lock.json b/package-lock.json index 2d49b6c..4640f23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "w_s10_challenge", "version": "0.0.1", "dependencies": { - "@reduxjs/toolkit": "^2.2.1", + "@reduxjs/toolkit": "^2.2.7", "axios": "^1.6.7", "cors": "^2.8.5", "express": "^4.18.2", @@ -16,6 +16,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^9.1.0", + "react-router": "^6.26.0", "react-router-dom": "^6.22.1", "styled-components": "^6.1.8", "yup": "^1.3.3" @@ -3183,14 +3184,15 @@ } }, "node_modules/@reduxjs/toolkit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.1.tgz", - "integrity": "sha512-8CREoqJovQW/5I4yvvijm/emUiCCmcs4Ev4XPWd4mizSO+dD3g5G6w34QK5AGeNrSH7qM8Fl66j4vuV7dpOdkw==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.7.tgz", + "integrity": "sha512-faI3cZbSdFb8yv9dhDTmGwclW0vk0z5o1cia+kf7gCbaCwHI5e+7tP57mJUv22pNcNbeA62GSrPpfrUfdXcQ6g==", + "license": "MIT", "dependencies": { "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", - "reselect": "^5.0.1" + "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18", @@ -4832,12 +4834,13 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -4845,7 +4848,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -4858,6 +4861,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -4865,7 +4869,8 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/bonjour-service": { "version": "1.2.1", @@ -4894,12 +4899,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -4995,6 +5001,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5637,6 +5644,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5651,6 +5659,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -7183,16 +7192,17 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -7223,6 +7233,15 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -7380,10 +7399,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7543,15 +7563,16 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -8982,6 +9003,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -11843,6 +11865,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13295,6 +13318,7 @@ "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -13364,9 +13388,10 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -13433,11 +13458,12 @@ } }, "node_modules/react-router": { - "version": "6.22.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.1.tgz", - "integrity": "sha512-0pdoRGwLtemnJqn1K0XHUbnKiX0S4X8CgvVVmHGOWmofESj31msHo/1YiqcJWK7Wxfq2a4uvvtS01KAQyWK/CQ==", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.0.tgz", + "integrity": "sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.15.1" + "@remix-run/router": "1.19.0" }, "engines": { "node": ">=14.0.0" @@ -13462,6 +13488,30 @@ "react-dom": ">=16.8" } }, + "node_modules/react-router-dom/node_modules/react-router": { + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.1.tgz", + "integrity": "sha512-0pdoRGwLtemnJqn1K0XHUbnKiX0S4X8CgvVVmHGOWmofESj31msHo/1YiqcJWK7Wxfq2a4uvvtS01KAQyWK/CQ==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.15.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router/node_modules/@remix-run/router": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.0.tgz", + "integrity": "sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -15157,6 +15207,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -15267,6 +15318,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -15686,14 +15738,16 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.0.0.tgz", - "integrity": "sha512-tZ5hqsWwww/8DislmrzXE3x+4f+v10H1z57mA2dWFrILb4i3xX+dPhTkcdR0DLyQztrhF2AUmO5nN085UYjd/Q==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", + "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", "mime-types": "^2.1.31", + "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, @@ -16256,10 +16310,11 @@ "dev": true }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index 81e181b..4969638 100755 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "webpack-dev-server": "^5.0.2" }, "dependencies": { - "@reduxjs/toolkit": "^2.2.1", + "@reduxjs/toolkit": "^2.2.7", "axios": "^1.6.7", "cors": "^2.8.5", "express": "^4.18.2", @@ -49,6 +49,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^9.1.0", + "react-router": "^6.26.0", "react-router-dom": "^6.22.1", "styled-components": "^6.1.8", "yup": "^1.3.3"