diff --git a/package-lock.json b/package-lock.json index 98d1f7fd..1b4d66fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@fortawesome/fontawesome-svg-core": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", + "@reduxjs/toolkit": "^2.0.1", "@sendgrid/mail": "^8.1.0", "@stanlemon/webdev": "^0.1.145", "bcryptjs": "^2.4.3", @@ -36,9 +37,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-fontawesome": "^1.7.1", - "react-redux": "^8.1.3", - "redux": "^4.2.1", - "redux-thunk": "^2.4.2", + "react-redux": "^9.0.3", "rsuite": "^5.47.0", "serve-static": "^1.15.0", "shortid": "^2.2.16", @@ -3066,6 +3065,29 @@ "streamx": "^2.15.0" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.0.1.tgz", + "integrity": "sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.0", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@rsuite/icon-font": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@rsuite/icon-font/-/icon-font-4.0.0.tgz", @@ -3608,15 +3630,6 @@ "@types/node": "*" } }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", - "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -9116,19 +9129,6 @@ "node": ">=8" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -9467,6 +9467,15 @@ "node": ">=0.10.0" } }, + "node_modules/immer": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz", + "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -14726,35 +14735,23 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-redux": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", - "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.0.3.tgz", + "integrity": "sha512-bilZStJN00qYqAXBpu/taUXv0tcuOrhBFD86fSERgYUm0+IHi/OQnqopbNalhgSo7+KMjSW5H/UTrWasXDvtug==", "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", "use-sync-external-store": "^1.0.0" }, "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4 || ^5.0.0-beta.0" + "@types/react": "^18.2.25", + "react": "^18.0", + "react-native": "^0.69.0", + "redux": "^5.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, "react-native": { "optional": true }, @@ -14763,11 +14760,6 @@ } } }, - "node_modules/react-redux/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, "node_modules/react-refresh": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", @@ -14848,19 +14840,16 @@ } }, "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.0.tgz", + "integrity": "sha512-blLIYmYetpZMET6Q6uCY7Jtl/Im5OBldy+vNPauA8vvsdqyt66oep4EUpAMWNHauTC6xa9JuRPhRB72rY82QGA==" }, "node_modules/redux-thunk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", "peerDependencies": { - "redux": "^4" + "redux": "^5.0.0" } }, "node_modules/reflect.getprototypeof": { @@ -15011,6 +15000,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/reselect": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.0.1.tgz", + "integrity": "sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", diff --git a/package.json b/package.json index 24425883..f1d51954 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "main": "server.js", "scripts": { "start": "node server.js", - "dev": "concurrently \"NODE_ENV=development nodemon --trace-warnings server.js\" \"npm run webpack:dev\"", + "start:dev": "NODE_ENV=development nodemon --trace-warnings server.js", + "dev": "concurrently \"npm run start:dev\" \"npm run webpack:dev\"", "lint": "eslint --ext .jsx --ext .js server.js src/** web/js/**", "lint:format": "eslint --ext .jsx --ext .js server.js src/** web/js/** --fix", "build": "npm run webpack:build", @@ -37,6 +38,7 @@ "@fortawesome/fontawesome-svg-core": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", + "@reduxjs/toolkit": "^2.0.1", "@sendgrid/mail": "^8.1.0", "@stanlemon/webdev": "^0.1.145", "bcryptjs": "^2.4.3", @@ -61,9 +63,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-fontawesome": "^1.7.1", - "react-redux": "^8.1.3", - "redux": "^4.2.1", - "redux-thunk": "^2.4.2", + "react-redux": "^9.0.3", "rsuite": "^5.47.0", "serve-static": "^1.15.0", "shortid": "^2.2.16", diff --git a/web/js/reducers/index.js b/web/js/reducers/index.js index 992b3d35..0fbf2033 100644 --- a/web/js/reducers/index.js +++ b/web/js/reducers/index.js @@ -27,6 +27,16 @@ import { GET_TASK_ERROR, } from "../actions/"; +export const initialState = { + user: null, + tags: [], + filter: FILTER_ALL, + page: 1, + tasks: {}, + loaded: [], + errors: [], +}; + // Ensure that we have valid dates in our tasks objects function formatTaskDates(task) { return Object.assign({}, task, { @@ -37,7 +47,7 @@ function formatTaskDates(task) { }); } -export function tags(state, action) { +export function tags(state = initialState.tags, action) { switch (action.type) { case LOAD_TAGS_SUCCESS: return [...action.tags]; @@ -46,7 +56,7 @@ export function tags(state, action) { } } -export function tasks(state, action) { +export function tasks(state = initialState.tasks, action) { switch (action.type) { case GET_TASK_SUCCESS: return { @@ -78,7 +88,7 @@ export function tasks(state, action) { } } -export function user(state, action) { +export function user(state = initialState.user, action) { switch (action.type) { case UNAUTHENTICATED_USER: return null; @@ -90,7 +100,7 @@ export function user(state, action) { } } -export function errors(state, action) { +export function errors(state = initialState.errors, action) { switch (action.type) { case ERROR: case LOAD_TAGS_ERROR: @@ -110,7 +120,7 @@ export function errors(state, action) { } } -export function loaded(state, action) { +export function loaded(state = initialState.loaded, action) { switch (action.type) { case LOAD_TAGS_ERROR: return uniq([...state, "tags"]); @@ -130,7 +140,7 @@ export function loaded(state, action) { } } -export function filter(state, action) { +export function filter(state = initialState.filter, action) { switch (action.type) { case SET_FILTER: return action.filter; @@ -139,7 +149,7 @@ export function filter(state, action) { } } -export function page(state, action) { +export function page(state = initialState.page, action) { switch (action.type) { case SET_PAGE: return action.page; @@ -148,18 +158,8 @@ export function page(state, action) { } } -export const initialState = { - user: null, - tags: [], - filter: FILTER_ALL, - page: 1, - tasks: {}, - loaded: [], - errors: [], -}; - export function reducers(state = initialState, action) { - const y = { + return { user: user(state.user, action), tags: tags(state.tags, action), filter: filter(state.filter, action), @@ -168,8 +168,6 @@ export function reducers(state = initialState, action) { loaded: loaded(state.loaded, action), errors: errors(state.errors, action), }; - //console.log("redux store = ", y); - return y; } export default reducers; diff --git a/web/js/store/index.js b/web/js/store/index.js index 37ce20e8..9eccafdd 100644 --- a/web/js/store/index.js +++ b/web/js/store/index.js @@ -1,6 +1,6 @@ -import { createStore, applyMiddleware } from "redux"; -import thunk from "redux-thunk"; -import reducer from "../reducers/"; +import { configureStore } from "@reduxjs/toolkit"; +import { user, tags, filter, page, tasks, loaded, errors } from "../reducers/"; + import UserService from "../lib/UserService"; import TaskService from "../lib/TaskService"; import TagService from "../lib/TagsService"; @@ -11,9 +11,22 @@ const services = { tagService: new TagService(), }; -const store = createStore( - reducer, - applyMiddleware(thunk.withExtraArgument(services)) -); +const store = configureStore({ + reducer: { + user, + tags, + filter, + page, + tasks, + loaded, + errors, + }, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + thunk: { + extraArgument: services, + }, + }), +}); export default store;