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 (
- -
-
- order details here
-
-
- )
- })
+ ordersLoading ? 'loading...' :
+ orders?.filter(order => filterSize === 'All' || order.size === filterSize)
+ .map(order => (
+ -
+
+
{order.customer} ordered a size {order.size} with {order.toppings?.length > 0 ? `${order.toppings.length} toppings` : 'no toppings'}
+
+
+ ))
}
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 (
-
- )
+ );
}
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"