From b29407b3382829e1ebea60a60ceb471bb1d8df8e Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Tue, 7 Dec 2021 21:27:11 +0000 Subject: [PATCH] Made into a very basic redux app --- package.json | 2 + src/components/TaskList.js | 31 ++++++++++++-- src/components/TaskList.stories.js | 8 ++-- src/lib/store.js | 50 ++++++++++++++++++++++ yarn.lock | 66 +++++++++++++++++++++++++++++- 5 files changed, 148 insertions(+), 9 deletions(-) create mode 100644 src/lib/store.js diff --git a/package.json b/package.json index 1edd5af4..9f541823 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,13 @@ "react-test-renderer": "^17.0.2" }, "dependencies": { + "@reduxjs/toolkit": "^1.6.2", "@testing-library/jest-dom": "^5.16.1", "@testing-library/react": "^12.1.2", "@testing-library/user-event": "^13.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-redux": "^7.2.6", "react-scripts": "^4.0.3", "web-vitals": "^2.1.2" }, diff --git a/src/components/TaskList.js b/src/components/TaskList.js index e2515bd8..e098d14e 100644 --- a/src/components/TaskList.js +++ b/src/components/TaskList.js @@ -1,8 +1,10 @@ import React from "react"; import PropTypes from "prop-types"; +import { useDispatch, useSelector } from "react-redux"; +import { updateTaskState } from "../lib/store"; import Task from "./Task"; -export default function TaskList({ loading, tasks, onPinTask, onArchiveTask }) { +export function PureTaskList({ loading, tasks, onPinTask, onArchiveTask }) { const events = { onPinTask, onArchiveTask, @@ -51,7 +53,7 @@ export default function TaskList({ loading, tasks, onPinTask, onArchiveTask }) { ); } -TaskList.propTypes = { +PureTaskList.propTypes = { /** Checks if it's in loading state */ loading: PropTypes.bool, /** The list of tasks */ @@ -61,6 +63,29 @@ TaskList.propTypes = { /** Event to change the task to archived */ onArchiveTask: PropTypes.func, }; -TaskList.defaultProps = { +PureTaskList.defaultProps = { loading: false, }; + +export function TaskList() { + const tasks = useSelector((state) => state.tasks); + const dispatch = useDispatch(); + + const pinTask = (value) => { + dispatch(updateTaskState({ id: value, newTaskState: "TASK_PINNED" })); + }; + const archiveTask = (value) => { + dispatch(updateTaskState({ id: value, newTaskState: "TASK_ARCHIVED" })); + }; + + const filteredTasks = tasks.filter( + (t) => t.state === "TASK_INBOX" || t.state === "TASK_PINNED" + ); + return ( + pinTask(task)} + onArchiveTask={(task) => archiveTask(task)} + /> + ); +} diff --git a/src/components/TaskList.stories.js b/src/components/TaskList.stories.js index b313fcd8..7bdadd5a 100644 --- a/src/components/TaskList.stories.js +++ b/src/components/TaskList.stories.js @@ -1,15 +1,15 @@ import React from "react"; -import TaskList from "./TaskList"; +import { PureTaskList } from "./TaskList"; import * as TaskStories from "./Task.stories"; export default { - component: TaskList, - title: "TaskList", + component: PureTaskList, + title: "PureTaskList", decorators: [(story) =>
{story()}
], }; -const Template = (args) => ; +const Template = (args) => ; export const Default = Template.bind({}); Default.args = { diff --git a/src/lib/store.js b/src/lib/store.js new file mode 100644 index 00000000..94ce2e28 --- /dev/null +++ b/src/lib/store.js @@ -0,0 +1,50 @@ +/* A simple redux store/actions/reducer implementation. + * A true app would be more complex and separated into different files. + */ +import { configureStore, createSlice } from "@reduxjs/toolkit"; + +/* + * The initial state of our store when the app loads. + * Usually, you would fetch this from a server. + */ +const defaultTasks = [ + { id: "1", title: "Something", state: "TASK_INBOX" }, + { id: "2", title: "Something more", state: "TASK_INBOX" }, + { id: "3", title: "Something else", state: "TASK_INBOX" }, + { id: "4", title: "Something again", state: "TASK_INBOX" }, +]; + +/* + * The store is created here. + * You can read more about Redux Toolkit's slices in the docs: + * https://redux-toolkit.js.org/api/createSlice + */ +const TasksSlice = createSlice({ + name: "tasks", + initialState: defaultTasks, + reducers: { + updateTaskState: (state, action) => { + const { id, newTaskState } = action.payload; + const task = state.findIndex((task) => task.id === id); + if (task >= 0) { + state[task].state = newTaskState; + } + }, + }, +}); + +// The actions contained in the slice are exported for usage in our components +export const { updateTaskState } = TasksSlice.actions; + +/* + * Our app's store configuration goes here. + * Read more about Redux's configureStore in the docs: + * https://redux-toolkit.js.org/api/configureStore + */ +const store = configureStore({ + reducer: { + tasks: TasksSlice.reducer, + }, +}); + +export default store; diff --git a/yarn.lock b/yarn.lock index d5810121..360286ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1283,7 +1283,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.8", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.8", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== @@ -1847,6 +1847,16 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.0.tgz#6734f8ebc106a0860dff7f92bf90df193f0935d7" integrity sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ== +"@reduxjs/toolkit@^1.6.2": + version "1.6.2" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.6.2.tgz#2f2b5365df77dd6697da28fdf44f33501ed9ba37" + integrity sha512-HbfI/hOVrAcMGAYsMWxw3UJyIoAS9JTdwddsjlr5w3S50tXhWb+EMyhIw+IAvCVCLETkzdjgH91RjDSYZekVBA== + dependencies: + immer "^9.0.6" + redux "^4.1.0" + redux-thunk "^2.3.0" + reselect "^4.0.0" + "@rollup/plugin-node-resolve@^7.1.1": version "7.1.3" resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz#80de384edfbd7bfc9101164910f86078151a3eca" @@ -3176,6 +3186,14 @@ dependencies: "@types/unist" "*" +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/html-minifier-terser@^5.0.0": version "5.1.2" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" @@ -3318,6 +3336,16 @@ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== +"@types/react-redux@^7.1.20": + version "7.1.20" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.20.tgz#42f0e61ababb621e12c66c96dda94c58423bd7df" + integrity sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + "@types/react-syntax-highlighter@11.0.5": version "11.0.5" resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.5.tgz#0d546261b4021e1f9d85b50401c0a42acb106087" @@ -8060,7 +8088,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.3.0: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -8333,6 +8361,11 @@ immer@8.0.1: resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== +immer@^9.0.6: + version "9.0.7" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.7.tgz#b6156bd7db55db7abc73fd2fdadf4e579a701075" + integrity sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -12487,6 +12520,18 @@ react-popper@^2.2.4: react-fast-compare "^3.0.1" warning "^4.0.2" +react-redux@^7.2.6: + version "7.2.6" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.6.tgz#49633a24fe552b5f9caf58feb8a138936ddfe9aa" + integrity sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@types/react-redux" "^7.1.20" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^17.0.2" + react-refresh@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.10.0.tgz#2f536c9660c0b9b1d500684d9e52a65e7404f7e3" @@ -12713,6 +12758,18 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redux-thunk@^2.3.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.1.tgz#0dd8042cf47868f4b29699941de03c9301a75714" + integrity sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q== + +redux@^4.0.0, redux@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" + integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== + dependencies: + "@babel/runtime" "^7.9.2" + refractor@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.5.0.tgz#334586f352dda4beaf354099b48c2d18e0819aec" @@ -12920,6 +12977,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +reselect@^4.0.0: + version "4.1.5" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6" + integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"