├── .DS_Store ├── 1.redux-core-only ├── .DS_Store ├── 1.redux-counter-project-1 │ ├── counter.js │ └── package.json ├── 2.redux-posts-project-2 │ ├── package.json │ └── posts.js └── 3.redux-only-posts-async-project-3 │ ├── app.js │ └── package.json ├── 2.react-redux-only ├── .DS_Store ├── react-redux-notes-app-project-4 │ ├── README.md │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── components │ │ │ ├── AddNotes.js │ │ │ ├── Form.css │ │ │ ├── NotesList.css │ │ │ └── NotesList.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── redux │ │ │ ├── actions │ │ │ │ ├── notesAction.js │ │ │ │ └── notesActionTypes.js │ │ │ ├── reducer │ │ │ │ └── noteReducer.js │ │ │ └── store │ │ │ │ └── store.js │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock └── react-redux-posts-app-project-5 │ ├── README.md │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── components │ ├── Form.css │ ├── Header.css │ ├── Posts.css │ ├── PostsList.js │ └── SearchPost.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── redux │ ├── actions │ │ ├── postActionTypes.js │ │ └── postActions.js │ ├── reducers │ │ └── postReducer.js │ └── store │ │ └── store.js │ ├── reportWebVitals.js │ ├── setupTests.js │ └── utils │ └── apiURL.js ├── 3.redux-toolkit-core-only ├── .DS_Store ├── 1.rtk-only-counter-project-6 │ ├── .DS_Store │ ├── app.js │ └── package.json └── 2.rtk-only-posts-project-7 │ ├── app.js │ └── package.json ├── README.md ├── react-redux-notes-app-final ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── components │ ├── AddNotes.js │ ├── Form.css │ ├── NotesList.css │ └── NotesList.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── redux │ ├── actions │ │ ├── notesAction.js │ │ └── notesActionTypes.js │ ├── reducer │ │ └── noteReducer.js │ └── store │ │ └── store.js │ ├── reportWebVitals.js │ └── setupTests.js ├── react-redux-notes-app-starter ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── components │ ├── AddNotes.js │ ├── Form.css │ ├── NotesList.css │ └── NotesList.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js ├── react-redux-posts-app-final ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── components │ │ ├── Form.css │ │ ├── Header.css │ │ ├── Posts.css │ │ ├── PostsList.js │ │ └── SearchPost.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── redux │ │ ├── actions │ │ │ ├── postActionTypes.js │ │ │ └── postActions.js │ │ ├── reducers │ │ │ └── postReducer.js │ │ └── store │ │ │ └── store.js │ ├── reportWebVitals.js │ ├── setupTests.js │ └── utils │ │ └── apiURL.js └── yarn.lock ├── react-redux-posts-app-starter ├── .gitignore ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── components │ ├── Form.css │ ├── Header.css │ ├── Posts.css │ ├── PostsList.js │ └── SearchPost.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js ├── rtk-income-expenses-project-final ├── .DS_Store ├── README.md ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.js │ ├── App.test.js │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── AuthRoute │ │ │ └── AuthRoute.js │ │ ├── Dashboard │ │ │ ├── AccountDetails.js │ │ │ ├── AccountList.js │ │ │ ├── AccountSummary.js │ │ │ ├── MainDashBoard.js │ │ │ └── TransactionList.js │ │ ├── Forms │ │ │ ├── AddAccount.js │ │ │ ├── AddTransaction.js │ │ │ ├── EditAccount.js │ │ │ ├── EditTransaction.js │ │ │ ├── Login.js │ │ │ └── Register.js │ │ ├── HomePage │ │ │ └── Home.js │ │ └── Navbar │ │ │ └── Navbar.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── redux │ │ ├── slice │ │ │ ├── accounts │ │ │ │ └── accountsSlice.js │ │ │ ├── transactions │ │ │ │ └── transactionSlice.js │ │ │ └── users │ │ │ │ └── usersSlice.js │ │ └── store │ │ │ └── store.js │ ├── reportWebVitals.js │ ├── setupTests.js │ └── utils │ │ └── baseURL.js ├── tailwind.config.js └── yarn-error.log ├── rtk-income-expenses-project-starter ├── .DS_Store ├── README.md ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.js │ ├── App.test.js │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── Dashboard │ │ │ ├── AccountDetails.js │ │ │ ├── AccountList.js │ │ │ ├── AccountSummary.js │ │ │ ├── MainDashBoard.js │ │ │ └── TransactionList.js │ │ ├── Forms │ │ │ ├── AddAccount.js │ │ │ ├── AddTransaction.js │ │ │ ├── EditAccount.js │ │ │ ├── EditTransaction.js │ │ │ ├── Login.js │ │ │ └── Register.js │ │ ├── HomePage │ │ │ └── Home.js │ │ └── Navbar │ │ │ └── Navbar.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js ├── tailwind.config.js └── yarn-error.log └── rtk-posts-app-final ├── README.md ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.css ├── App.js ├── App.test.js ├── components │ ├── Form.css │ ├── Header.css │ ├── Posts.css │ ├── PostsList.js │ └── SearchPost.js ├── index.css ├── index.js ├── logo.svg ├── redux │ ├── slice │ │ └── postsSlice.js │ └── store │ │ └── store.js ├── reportWebVitals.js ├── setupTests.js └── utils │ └── apiURL.js └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/.DS_Store -------------------------------------------------------------------------------- /1.redux-core-only/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/1.redux-core-only/.DS_Store -------------------------------------------------------------------------------- /1.redux-core-only/1.redux-counter-project-1/counter.js: -------------------------------------------------------------------------------- 1 | const redux = require("redux"); 2 | const { createStore } = redux; 3 | 4 | //Counter Action Types 5 | const INCREMENT = "INCREMENT"; 6 | const DECREMENT = "DECREMENT"; 7 | const RESET = "RESET"; 8 | const INCREMENT_BY_AMT = "INCREMENT_BY_AMT"; 9 | 10 | //Counter initial state 11 | const initialState = { 12 | count: 0, 13 | }; 14 | { 15 | type: "Add"; 16 | } 17 | //Counter Action Creators 18 | const incrementAction = () => { 19 | return { 20 | type: INCREMENT, 21 | }; 22 | }; 23 | 24 | const decrementAction = () => { 25 | return { 26 | type: DECREMENT, 27 | }; 28 | }; 29 | 30 | const resetAction = () => { 31 | return { 32 | type: RESET, 33 | }; 34 | }; 35 | 36 | const incrementByAmtAction = (amt) => { 37 | return { 38 | type: INCREMENT_BY_AMT, 39 | payload: amt, 40 | }; 41 | }; 42 | 43 | //Counter Reducer 44 | const counterReducer = (state = initialState, action) => { 45 | switch (action.type) { 46 | case INCREMENT: 47 | return { 48 | count: state.count + 1, 49 | }; 50 | case DECREMENT: 51 | return { 52 | count: state.count - 1, 53 | }; 54 | case RESET: 55 | return { 56 | count: 0, 57 | }; 58 | case INCREMENT_BY_AMT: 59 | return { 60 | count: state.count + action.payload, 61 | }; 62 | default: 63 | return state; 64 | } 65 | }; 66 | 67 | //Counter store 68 | const store = createStore(counterReducer); 69 | 70 | //Subscribe: It means that whenever the state changes, the callback function will be called. 71 | 72 | const unSubscribe = store.subscribe(() => { 73 | console.log(store.getState()); 74 | }); 75 | 76 | //Dispatch 77 | store.dispatch(incrementAction()); 78 | store.dispatch(incrementAction()); 79 | store.dispatch(incrementByAmtAction(5)); 80 | -------------------------------------------------------------------------------- /1.redux-core-only/1.redux-counter-project-1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-counter", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "redux": "^4.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /1.redux-core-only/2.redux-posts-project-2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-counter", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "redux": "^4.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /1.redux-core-only/2.redux-posts-project-2/posts.js: -------------------------------------------------------------------------------- 1 | const redux = require("redux"); 2 | const { createStore } = redux; 3 | //Add Post Action Type 4 | const ADD_POST = "ADD_POST"; 5 | const REMOVE_POST = "REMOVE_POST"; 6 | 7 | //Post initial state 8 | const initialState = { 9 | posts: [], 10 | }; 11 | 12 | //Add Post Action Creator 13 | const addPostAction = post => { 14 | return { 15 | type: ADD_POST, 16 | post, 17 | }; 18 | }; 19 | 20 | //Remove Post Action Creator 21 | const removePostAction = id => { 22 | return { 23 | type: REMOVE_POST, 24 | id, 25 | }; 26 | }; 27 | 28 | //Post Reducer 29 | postsReducer = (state = initialState, action) => { 30 | switch (action.type) { 31 | case ADD_POST: 32 | return { 33 | posts: [...state.posts, action.post], 34 | }; 35 | case REMOVE_POST: 36 | return { 37 | posts: state.posts.filter(post => post.id !== action.id), 38 | }; 39 | default: 40 | return state; 41 | } 42 | }; 43 | 44 | //Post store 45 | const store = createStore(postsReducer); 46 | 47 | //Subscribe: It means that whenever the state changes, the callback function will be called. 48 | const unSubscribe = store.subscribe(() => { 49 | console.log(store.getState()); 50 | }); 51 | 52 | //Dispatch 53 | store.dispatch(addPostAction({ id: 1, title: "Post 1" })); 54 | store.dispatch(addPostAction({ id: 2, title: "Post 2" })); 55 | 56 | store.dispatch(removePostAction(1)); 57 | 58 | unSubscribe(); 59 | -------------------------------------------------------------------------------- /1.redux-core-only/3.redux-only-posts-async-project-3/app.js: -------------------------------------------------------------------------------- 1 | const { applyMiddleware, createStore } = require("redux"); 2 | const axios = require("axios"); 3 | const thunkMiddleware = require("redux-thunk").default; 4 | 5 | //Post action types 6 | const FETCH_POSTS_REQUEST = "FETCH_POSTS_REQUEST"; 7 | const FETCH_POSTS_SUCCESS = "FETCH_POSTS_SUCCESS"; 8 | const FETCH_POSTS_FAILURE = "FETCH_POSTS_FAILURE"; 9 | 10 | //Async action creator 11 | const fetchPostRequest = () => { 12 | return { 13 | type: FETCH_POSTS_REQUEST, 14 | }; 15 | }; 16 | 17 | //success action creator 18 | const fetchPostSuccess = (posts) => { 19 | return { 20 | type: FETCH_POSTS_SUCCESS, 21 | payload: posts, 22 | }; 23 | }; 24 | 25 | //failure action creator 26 | const fetchPostFailure = (error) => { 27 | return { 28 | type: FETCH_POSTS_FAILURE, 29 | payload: error, 30 | }; 31 | }; 32 | 33 | //Async action creator 34 | const fetchPosts = () => { 35 | return async (dispatch) => { 36 | dispatch(fetchPostRequest()); 37 | try { 38 | const response = await axios.get( 39 | "https://jsonplaceholder.typicode.com/posts" 40 | ); 41 | dispatch(fetchPostSuccess(response)); 42 | } catch (error) { 43 | dispatch(fetchPostFailure(error.message)); 44 | } 45 | }; 46 | }; 47 | 48 | //Post reducer 49 | const postReducer = ( 50 | state = { posts: [], loading: false, error: "" }, 51 | action 52 | ) => { 53 | switch (action.type) { 54 | case FETCH_POSTS_REQUEST: 55 | return { 56 | ...state, 57 | loading: true, 58 | }; 59 | case FETCH_POSTS_SUCCESS: 60 | return { 61 | ...state, 62 | loading: false, 63 | posts: action.payload, 64 | error: "", 65 | }; 66 | case FETCH_POSTS_FAILURE: 67 | return { 68 | ...state, 69 | loading: false, 70 | posts: [], 71 | error: action.payload, 72 | }; 73 | default: 74 | return state; 75 | } 76 | }; 77 | 78 | //store 79 | const store = createStore(postReducer, applyMiddleware(thunkMiddleware)); 80 | 81 | //subscribe 82 | store.subscribe(() => { 83 | console.log(store.getState().posts); 84 | }); 85 | 86 | //dispatch 87 | store.dispatch(fetchPosts()); 88 | -------------------------------------------------------------------------------- /1.redux-core-only/3.redux-only-posts-async-project-3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-only", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "axios": "^0.27.2", 14 | "redux": "^4.2.0", 15 | "redux-logger": "^3.0.6", 16 | "redux-thunk": "^2.4.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /2.react-redux-only/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/2.react-redux-only/.DS_Store -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.3.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "axios": "^0.27.2", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0", 12 | "react-redux": "^8.0.4", 13 | "react-scripts": "5.0.1", 14 | "redux": "^4.2.0", 15 | "redux-logger": "^3.0.6", 16 | "redux-thunk": "^2.4.1", 17 | "web-vitals": "^2.1.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": [ 27 | "react-app", 28 | "react-app/jest" 29 | ] 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "redux-devtools-extension": "^2.13.9" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/2.react-redux-only/react-redux-notes-app-project-4/public/favicon.ico -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/2.react-redux-only/react-redux-notes-app-project-4/public/logo192.png -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/2.react-redux-only/react-redux-notes-app-project-4/public/logo512.png -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | import AddNotes from "./components/AddNotes"; 3 | import NotesList from "./components/NotesList"; 4 | 5 | function App() { 6 | return ( 7 |
8 | 9 | 10 |
11 | ); 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/components/AddNotes.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { useDispatch } from "react-redux"; 3 | import { addNoteAction } from "../redux/actions/notesAction"; 4 | import "./Form.css"; 5 | 6 | const AddNotes = () => { 7 | //dispatch 8 | const dispatch = useDispatch(); 9 | const [note, setNote] = useState({ 10 | title: "", 11 | content: "", 12 | }); 13 | 14 | const handleChange = e => { 15 | setNote({ 16 | ...note, 17 | [e.target.name]: e.target.value, 18 | }); 19 | }; 20 | 21 | const handleSubmit = e => { 22 | //prevent empty notes 23 | if (note.title === "" || note.content === "") { 24 | return alert("Please fill in the form"); 25 | } 26 | e.preventDefault(); 27 | //dispatch action 28 | dispatch(addNoteAction(note)); 29 | console.log(note); 30 | //reset form 31 | setNote({ 32 | title: "", 33 | content: "", 34 | }); 35 | }; 36 | 37 | return ( 38 |
39 |
40 |

Notes Taking App Built with React Redux

41 |

42 | This is a simple notes taking app built with React Redux. You can add 43 |

44 |
45 |
46 | 53 | 61 | 64 |
65 | Enroll in the course 66 |
67 | ); 68 | }; 69 | 70 | export default AddNotes; 71 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/components/Form.css: -------------------------------------------------------------------------------- 1 | .formContainer { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | width: 100%; 7 | padding: 20px; 8 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 9 | } 10 | h3 { 11 | margin: 0; 12 | padding: 0; 13 | font-size: 2.5rem; 14 | font-weight: bold; 15 | } 16 | 17 | p { 18 | margin: 10px; 19 | padding: 0; 20 | font-size: 1rem; 21 | font-weight: 400; 22 | } 23 | form { 24 | display: flex; 25 | flex-direction: row; 26 | align-items: center; 27 | justify-content: center; 28 | width: auto; 29 | height: 100%; 30 | } 31 | 32 | form input { 33 | width: 80%; 34 | height: 100%; 35 | border: 1px solid #ccc; 36 | outline: none; 37 | padding: 10px; 38 | font-size: 1.1rem; 39 | border-radius: 5px; 40 | margin: 0 10px; 41 | } 42 | 43 | .btn-enroll { 44 | background-color: #4caf50; 45 | color: #fff; 46 | } 47 | 48 | button { 49 | } 50 | .add-btn { 51 | background-color: #4caf50; 52 | color: #fff; 53 | width: 100px; 54 | height: 40px; 55 | border: none; 56 | outline: none; 57 | border-radius: 5px; 58 | font-size: 1.1rem; 59 | cursor: pointer; 60 | width: 70%; 61 | } 62 | a { 63 | text-decoration: none; 64 | color: white; 65 | padding: 5px; 66 | border-radius: 5px; 67 | background-color: red; 68 | padding: 10px; 69 | margin: 10px; 70 | } 71 | 72 | a:hover { 73 | transform: scale(1.1); 74 | transition: all 0.3s ease-in-out; 75 | } 76 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/components/NotesList.css: -------------------------------------------------------------------------------- 1 | .item-container { 2 | display: flex; 3 | flex-direction: row; 4 | justify-content: center; 5 | width: 100%; 6 | align-items: center; 7 | padding: 10px; 8 | } 9 | 10 | .item-content { 11 | width: 800px; 12 | padding: 10px; 13 | background-color: white; 14 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 15 | } 16 | 17 | .item-content button { 18 | width: 100%; 19 | height: 40px; 20 | border: none; 21 | outline: none; 22 | border-radius: 5px; 23 | font-size: 1.1rem; 24 | cursor: pointer; 25 | background-color: #4caf50; 26 | color: #fff; 27 | } 28 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/components/NotesList.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | import { 4 | deleteNoteAction, 5 | fetchNotesAction, 6 | } from "../redux/actions/notesAction"; 7 | 8 | import "./NotesList.css"; 9 | 10 | const NotesList = () => { 11 | //dispatch 12 | const dispatch = useDispatch(); 13 | useEffect(() => { 14 | dispatch(fetchNotesAction()); 15 | }, []); 16 | //get data from store 17 | const notes = useSelector(storeData => { 18 | return storeData.notes; 19 | }); 20 | 21 | return ( 22 | <> 23 |

Notes List

24 | 25 | {notes.map(note => ( 26 |
27 |
28 |

{note.title}

29 |

{note.content}

30 | 33 |
34 |
35 | ))} 36 | 37 | ); 38 | }; 39 | 40 | export default NotesList; 41 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/index.css: -------------------------------------------------------------------------------- 1 | /* body { 2 | background-color: #f5f5f5; 3 | } 4 | 5 | code { 6 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 7 | monospace; 8 | } */ 9 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { Provider } from "react-redux"; 4 | import "./index.css"; 5 | import App from "./App"; 6 | 7 | import reportWebVitals from "./reportWebVitals"; 8 | import store from "./redux/store/store"; 9 | 10 | const root = ReactDOM.createRoot(document.getElementById("root")); 11 | root.render( 12 | 13 | 14 | 15 | ); 16 | 17 | // If you want to start measuring performance in your app, pass a function 18 | // to log results (for example: reportWebVitals(console.log)) 19 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 20 | reportWebVitals(); 21 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/redux/actions/notesAction.js: -------------------------------------------------------------------------------- 1 | import { ADD_NOTE, DELETE_NOTE, FETCH_NOTES } from "./notesActionTypes"; 2 | 3 | //actions 4 | //Add note action creator 5 | export const addNoteAction = note => { 6 | return { 7 | type: ADD_NOTE, 8 | payload: note, 9 | }; 10 | }; 11 | //Delete note action creator 12 | export const deleteNoteAction = id => { 13 | return { 14 | type: DELETE_NOTE, 15 | payload: id, 16 | }; 17 | }; 18 | //Fetch notes action creator 19 | export const fetchNotesAction = () => { 20 | return { 21 | type: FETCH_NOTES, 22 | }; 23 | }; 24 | //store 25 | //dispatch 26 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/redux/actions/notesActionTypes.js: -------------------------------------------------------------------------------- 1 | export const ADD_NOTE = "ADD_NOTE"; 2 | export const DELETE_NOTE = "DELETE_NOTE"; 3 | export const FETCH_NOTES = "FETCH_NOTES"; 4 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/redux/reducer/noteReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_NOTE, 3 | DELETE_NOTE, 4 | FETCH_NOTES, 5 | } from "../actions/notesActionTypes"; 6 | 7 | //Initialstate 8 | const initialstate = { 9 | notes: [], 10 | }; 11 | 12 | //note reducer 13 | const notesReducer = (state = initialstate, action) => { 14 | switch (action.type) { 15 | case ADD_NOTE: 16 | //new note 17 | const newNote = { 18 | id: Math.random(), 19 | title: action.payload.title, 20 | content: action.payload.content, 21 | }; 22 | //add note into storage 23 | const updatedNotes = [...state.notes, newNote]; 24 | localStorage.setItem("notes", JSON.stringify(updatedNotes)); 25 | return { 26 | notes: [...state.notes, newNote], 27 | }; 28 | //fetch notes 29 | case FETCH_NOTES: 30 | return { 31 | notes: JSON.parse(localStorage.getItem("notes")) 32 | ? JSON.parse(localStorage.getItem("notes")) 33 | : [], 34 | }; 35 | //Delete note 36 | case DELETE_NOTE: 37 | const filteredNotes = state.notes.filter( 38 | note => note.id !== action.payload 39 | ); 40 | //Resave to localstorage 41 | localStorage.setItem("notes", JSON.stringify(filteredNotes)); 42 | return { 43 | ...state, 44 | notes: filteredNotes, 45 | }; 46 | default: 47 | return state; 48 | } 49 | }; 50 | 51 | export default notesReducer; 52 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/redux/store/store.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "redux"; 2 | import { composeWithDevTools } from "redux-devtools-extension"; 3 | import notesReducer from "../reducer/noteReducer"; 4 | 5 | const store = createStore(notesReducer, composeWithDevTools()); 6 | 7 | export default store; 8 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-notes-app-project-4/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.3.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "axios": "^0.27.2", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0", 12 | "react-redux": "^8.0.5", 13 | "react-scripts": "5.0.1", 14 | "redux": "^4.2.0", 15 | "redux-logger": "^3.0.6", 16 | "redux-thunk": "^2.4.2", 17 | "web-vitals": "^2.1.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": [ 27 | "react-app", 28 | "react-app/jest" 29 | ] 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "redux-devtools-extension": "^2.13.9" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/2.react-redux-only/react-redux-posts-app-project-5/public/favicon.ico -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/2.react-redux-only/react-redux-posts-app-project-5/public/logo192.png -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/2.react-redux-only/react-redux-posts-app-project-5/public/logo512.png -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | 3 | import NotesList from "./components/PostsList"; 4 | 5 | function App() { 6 | return ; 7 | } 8 | 9 | export default App; 10 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/components/Form.css: -------------------------------------------------------------------------------- 1 | .form-header { 2 | background-color: #22577a; 3 | color: #fff; 4 | padding: 10px; 5 | text-align: center; 6 | } 7 | form { 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | justify-content: center; 12 | width: 100%; 13 | height: 100%; 14 | margin: 10px; 15 | } 16 | 17 | form input { 18 | border: 1px solid #ccc; 19 | outline: none; 20 | font-size: 1.1rem; 21 | border-radius: 5px; 22 | margin: 5px; 23 | padding: 5px; 24 | } 25 | 26 | form button { 27 | border: 1px solid #ccc; 28 | outline: none; 29 | color: #fff; 30 | cursor: pointer; 31 | padding: 8px; 32 | background-color: #22577a; 33 | width: 100px; 34 | border-radius: 5px; 35 | margin: 5px; 36 | } 37 | 38 | form button:hover { 39 | background-color: #1b435e; 40 | transform: scale(1.1); 41 | transition: all 0.2s ease-in-out; 42 | } 43 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/components/Header.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: #333; 3 | color: #fff; 4 | padding: 10px; 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/components/Posts.css: -------------------------------------------------------------------------------- 1 | .posts-list { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | width: 100%; 6 | background-color: #f5f5f5; 7 | } 8 | 9 | .post-details { 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | width: 80%; 14 | margin: 10px; 15 | padding: 10px; 16 | border: 1px solid #fff; 17 | border-radius: 5px; 18 | background-color: #fff; 19 | } 20 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/components/PostsList.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | import SearchPost from "./SearchPost"; 4 | import "./Posts.css"; 5 | import { fetchPostsAction } from "../redux/actions/postActions"; 6 | 7 | const PostsList = () => { 8 | //dispatch 9 | const dispatch = useDispatch(); 10 | useEffect(() => { 11 | dispatch(fetchPostsAction()); 12 | }, []); 13 | 14 | //get data from store 15 | const { loading, error, posts, post } = useSelector(data => data); 16 | 17 | console.log(loading, error, posts, post); 18 | 19 | return ( 20 | <> 21 | 22 |
23 |

Total Posts {posts.length}

24 | {loading ? ( 25 |

Loading

26 | ) : error ? ( 27 |

28 | {error.response.status && "No Post Found"} 29 |

30 | ) : ( 31 | posts.map(post => ( 32 |
33 |

{post.title}

34 |

{post.body}

35 |
36 | )) 37 | )} 38 |
39 | 40 | ); 41 | }; 42 | 43 | export default PostsList; 44 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/components/SearchPost.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useSelector, useDispatch } from "react-redux"; 3 | import { fetchPostAction } from "../redux/actions/postActions"; 4 | 5 | import "./Form.css"; 6 | const SearchPost = () => { 7 | const dispatch = useDispatch(); 8 | //search form state 9 | const [search, setSearch] = React.useState(""); 10 | //search form submit handler 11 | const handleSubmit = e => { 12 | e.preventDefault(); 13 | if (search === "") { 14 | return alert("Please provide a value"); 15 | } 16 | dispatch(fetchPostAction(search)); 17 | }; 18 | 19 | return ( 20 |
21 |
22 |

React Redux Project

23 |

24 | This project is a simple React Redux project that fetches data with 25 | search functionality from an API 26 |

27 |
28 |
29 | setSearch(e.target.value)} 34 | /> 35 | 36 |
37 |
38 | ); 39 | }; 40 | 41 | export default SearchPost; 42 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | import { Provider } from "react-redux"; 7 | import store from "./redux/store/store"; 8 | 9 | const root = ReactDOM.createRoot(document.getElementById("root")); 10 | root.render( 11 | 12 | 13 | 14 | ); 15 | 16 | // If you want to start measuring performance in your app, pass a function 17 | // to log results (for example: reportWebVitals(console.log)) 18 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 19 | reportWebVitals(); 20 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/redux/actions/postActionTypes.js: -------------------------------------------------------------------------------- 1 | //notes action types 2 | export const FETCH_POSTS_SUCCESS = "FETCH_POSTS_SUCCESS"; 3 | export const FETCH_POSTS_FAILURE = "FETCH_POSTS_FAILURE"; 4 | export const FETCH_POSTS_REQUEST = "FETCH_POSTS_REQUEST"; 5 | 6 | export const SEARCH_POST_REQUEST = "SEARCH_POST_REQUEST"; 7 | export const SEARCH_POST_SUCCESS = "SEARCH_POST_SUCCESS"; 8 | export const SEARCH_POST_FAILURE = "SEARCH_POST_FAILURE"; 9 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/redux/actions/postActions.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { 3 | FETCH_POSTS_SUCCESS, 4 | FETCH_POSTS_FAILURE, 5 | FETCH_POSTS_REQUEST, 6 | SEARCH_POST_FAILURE, 7 | SEARCH_POST_REQUEST, 8 | SEARCH_POST_SUCCESS, 9 | } from "./postActionTypes"; 10 | const apiURL = "https://jsonplaceholder.typicode.com/posts"; 11 | //Actions Creators 12 | //1. fetch posts (request started, success, error) 13 | 14 | //request started 15 | const fetchPostsRequest = () => { 16 | return { 17 | type: FETCH_POSTS_REQUEST, 18 | }; 19 | }; 20 | 21 | //success 22 | const fetchPostsSuccess = posts => { 23 | return { 24 | type: FETCH_POSTS_SUCCESS, 25 | payload: posts, 26 | }; 27 | }; 28 | 29 | //error action creator 30 | const fetchPostsErr = error => { 31 | return { 32 | type: FETCH_POSTS_FAILURE, 33 | payload: error, 34 | }; 35 | }; 36 | 37 | //fetch posts action 38 | export const fetchPostsAction = () => { 39 | return async dispatch => { 40 | //request action 41 | dispatch(fetchPostsRequest()); 42 | try { 43 | //make http request 44 | const res = await axios.get(apiURL); 45 | //success action 46 | dispatch(fetchPostsSuccess(res.data)); 47 | } catch (error) { 48 | //error action 49 | dispatch(fetchPostsErr(error)); 50 | } 51 | }; 52 | }; 53 | 54 | //2. fetch post (request started, success, error) 55 | //request action 56 | const fetchPostRequest = () => { 57 | return { 58 | type: SEARCH_POST_REQUEST, 59 | }; 60 | }; 61 | //success 62 | const fetchPostSuccess = post => { 63 | return { 64 | type: SEARCH_POST_SUCCESS, 65 | payload: post, 66 | }; 67 | }; 68 | 69 | //error action creator 70 | const fetchPostErr = error => { 71 | return { 72 | type: SEARCH_POST_FAILURE, 73 | payload: error, 74 | }; 75 | }; 76 | 77 | //single post action 78 | export const fetchPostAction = id => { 79 | return async dispatch => { 80 | dispatch(fetchPostRequest()); 81 | try { 82 | //make http request 83 | const res = await axios.get(`${apiURL}/${id}`); 84 | //success 85 | dispatch(fetchPostSuccess(res.data)); 86 | } catch (error) { 87 | dispatch(fetchPostErr(error)); 88 | } 89 | }; 90 | }; 91 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/redux/reducers/postReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | FETCH_POSTS_SUCCESS, 3 | FETCH_POSTS_FAILURE, 4 | FETCH_POSTS_REQUEST, 5 | SEARCH_POST_FAILURE, 6 | SEARCH_POST_REQUEST, 7 | SEARCH_POST_SUCCESS, 8 | } from "../actions/postActionTypes"; 9 | 10 | //initial state 11 | const initialState = { 12 | loading: false, 13 | error: "", 14 | posts: [], 15 | post: {}, 16 | }; 17 | 18 | //reducers 19 | export const postsReducer = (state = initialState, action) => { 20 | switch (action.type) { 21 | case FETCH_POSTS_REQUEST: 22 | return { 23 | ...state, 24 | loading: true, 25 | }; 26 | //success 27 | case FETCH_POSTS_SUCCESS: 28 | return { 29 | ...state, 30 | posts: action.payload, 31 | loading: false, 32 | }; 33 | //error 34 | case FETCH_POSTS_FAILURE: 35 | return { 36 | ...state, 37 | posts: [], 38 | error: action.payload, 39 | loading: false, 40 | }; 41 | //========SEARCH SINGLE POST ======= 42 | case SEARCH_POST_REQUEST: 43 | return { 44 | ...state, 45 | loading: true, 46 | }; 47 | case SEARCH_POST_SUCCESS: 48 | return { 49 | ...state, 50 | posts: [action.payload], 51 | loading: false, 52 | }; 53 | case SEARCH_POST_FAILURE: 54 | return { 55 | ...state, 56 | posts: [], 57 | error: action.payload, 58 | loading: false, 59 | }; 60 | //return default state 61 | default: 62 | return state; 63 | } 64 | }; 65 | //store 66 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/redux/store/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from "redux"; 2 | import { composeWithDevTools } from "redux-devtools-extension"; 3 | import reduxThunk from "redux-thunk"; 4 | import { postsReducer } from "../reducers/postReducer"; 5 | 6 | //combine all middlewares 7 | const middlewares = [reduxThunk]; 8 | const middlewareEnhancers = applyMiddleware(...middlewares); 9 | const store = createStore( 10 | postsReducer, 11 | composeWithDevTools(middlewareEnhancers) 12 | ); 13 | 14 | export default store; 15 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /2.react-redux-only/react-redux-posts-app-project-5/src/utils/apiURL.js: -------------------------------------------------------------------------------- 1 | const apiURL = "https://jsonplaceholder.typicode.com/posts"; 2 | export default apiURL; 3 | -------------------------------------------------------------------------------- /3.redux-toolkit-core-only/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/3.redux-toolkit-core-only/.DS_Store -------------------------------------------------------------------------------- /3.redux-toolkit-core-only/1.rtk-only-counter-project-6/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/3.redux-toolkit-core-only/1.rtk-only-counter-project-6/.DS_Store -------------------------------------------------------------------------------- /3.redux-toolkit-core-only/1.rtk-only-counter-project-6/app.js: -------------------------------------------------------------------------------- 1 | //configure store 2 | const { configureStore, createSlice } = require("@reduxjs/toolkit"); 3 | 4 | //state for counter 5 | const initialState = { 6 | counter: 0, 7 | }; 8 | 9 | //Slice 10 | const counterSlice = createSlice({ 11 | name: "counter", //name of the slice 12 | initialState, 13 | reducers: { 14 | increment: state => { 15 | state.counter += 1; 16 | }, 17 | decrement: state => { 18 | state.counter -= 1; 19 | }, 20 | 21 | incrementByAmount: (state, action) => { 22 | state.counter += action.payload; 23 | }, 24 | reset: state => { 25 | state.counter = 0; 26 | }, 27 | }, 28 | //extra reducers method 1 29 | // extraReducers: { 30 | // "notes/addNote": (state, action) => { 31 | // state.counter += 1; 32 | // }, 33 | // }, 34 | //The key we specify in the extraReducers object is the action name and the value in a differeent createSlice that we want to listen to 35 | 36 | //extra reducers method 2 (Most recommended) 37 | extraReducers: builder => { 38 | builder.addCase("notes/addNote", (state, action) => { 39 | state.counter += 1; 40 | }); 41 | }, 42 | }); 43 | 44 | //Export actions 45 | const { increment, decrement, incrementByAmount, reset } = counterSlice.actions; 46 | 47 | //reducers 48 | const counterReducer = counterSlice.reducer; 49 | 50 | const store = configureStore({ 51 | reducer: { 52 | counter: counterReducer, 53 | }, 54 | }); 55 | 56 | //subscribe to store 57 | const unSubscribe = store.subscribe(() => { 58 | console.log(store.getState()); 59 | }); 60 | 61 | //dispatch actions 62 | store.dispatch(increment()); 63 | store.dispatch(increment()); 64 | store.dispatch(incrementByAmount(10)); 65 | 66 | //unsubscribe 67 | unSubscribe(); 68 | -------------------------------------------------------------------------------- /3.redux-toolkit-core-only/1.rtk-only-counter-project-6/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rtk-only", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@reduxjs/toolkit": "^1.8.5", 14 | "axios": "^0.27.2", 15 | "redux-logger": "^3.0.6" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /3.redux-toolkit-core-only/2.rtk-only-posts-project-7/app.js: -------------------------------------------------------------------------------- 1 | const { 2 | createAsyncThunk, 3 | createSlice, 4 | configureStore, 5 | } = require("@reduxjs/toolkit"); 6 | const axios = require("axios"); 7 | 8 | const API = "https://jsonplaceholder.typicode.com/posts"; 9 | 10 | //Initial state 11 | const initialState = { 12 | posts: [], 13 | loading: false, 14 | error: null, 15 | }; 16 | //create Async Thunk 17 | const fetchPosts = createAsyncThunk("posts/fetchPosts", async () => { 18 | const res = await axios.get(API); 19 | return res.data; //grabbing the data only 20 | }); 21 | //slice 22 | 23 | const postsSlice = createSlice({ 24 | name: "posts", 25 | initialState, 26 | extraReducers: (builder) => { 27 | //Handle lifecycle - pending-success, rejected 28 | //pending 29 | builder.addCase(fetchPosts.pending, (state, action) => { 30 | state.loading = true; 31 | }); 32 | //fulfilled 33 | builder.addCase(fetchPosts.fulfilled, (state, action) => { 34 | state.posts = action.payload; 35 | state.loading = false; 36 | }); 37 | //rejected 38 | builder.addCase(fetchPosts.rejected, (state, action) => { 39 | state.posts = []; 40 | state.loading = false; 41 | state.error = action.payload; 42 | }); 43 | }, 44 | }); 45 | 46 | //generate reducer 47 | const postsReducer = postsSlice.reducer; 48 | 49 | //store 50 | const store = configureStore({ 51 | reducer: postsReducer, 52 | }); 53 | 54 | //dispatch 55 | store.subscribe(() => { 56 | console.log(store.getState()); 57 | }); 58 | store.dispatch(fetchPosts()); 59 | -------------------------------------------------------------------------------- /3.redux-toolkit-core-only/2.rtk-only-posts-project-7/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rtk-only", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@reduxjs/toolkit": "^1.8.5", 14 | "axios": "^0.27.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.3.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "axios": "^0.27.2", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0", 12 | "react-redux": "^8.0.4", 13 | "react-scripts": "5.0.1", 14 | "redux": "^4.2.0", 15 | "redux-logger": "^3.0.6", 16 | "redux-thunk": "^2.4.1", 17 | "web-vitals": "^2.1.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": [ 27 | "react-app", 28 | "react-app/jest" 29 | ] 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "redux-devtools-extension": "^2.13.9" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-notes-app-final/public/favicon.ico -------------------------------------------------------------------------------- /react-redux-notes-app-final/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-notes-app-final/public/logo192.png -------------------------------------------------------------------------------- /react-redux-notes-app-final/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-notes-app-final/public/logo512.png -------------------------------------------------------------------------------- /react-redux-notes-app-final/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | import AddNotes from "./components/AddNotes"; 3 | import NotesList from "./components/NotesList"; 4 | 5 | function App() { 6 | return ( 7 |
8 | 9 | 10 |
11 | ); 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/components/AddNotes.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { useDispatch } from "react-redux"; 3 | import { addNoteAction } from "../redux/actions/notesAction"; 4 | import "./Form.css"; 5 | 6 | const AddNotes = () => { 7 | //dispatch 8 | const dispatch = useDispatch(); 9 | const [note, setNote] = useState({ 10 | title: "", 11 | content: "", 12 | }); 13 | 14 | const handleChange = e => { 15 | setNote({ 16 | ...note, 17 | [e.target.name]: e.target.value, 18 | }); 19 | }; 20 | 21 | const handleSubmit = e => { 22 | //prevent empty notes 23 | if (note.title === "" || note.content === "") { 24 | return alert("Please fill in the form"); 25 | } 26 | e.preventDefault(); 27 | //dispatch action 28 | dispatch(addNoteAction(note)); 29 | console.log(note); 30 | //reset form 31 | setNote({ 32 | title: "", 33 | content: "", 34 | }); 35 | }; 36 | 37 | return ( 38 |
39 |
40 |

Notes Taking App Built with React Redux

41 |

42 | This is a simple notes taking app built with React Redux. You can add 43 |

44 |
45 |
46 | 53 | 61 | 64 |
65 | Enroll in the course 66 |
67 | ); 68 | }; 69 | 70 | export default AddNotes; 71 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/components/Form.css: -------------------------------------------------------------------------------- 1 | .formContainer { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | width: 100%; 7 | padding: 20px; 8 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 9 | } 10 | h3 { 11 | margin: 0; 12 | padding: 0; 13 | font-size: 2.5rem; 14 | font-weight: bold; 15 | } 16 | 17 | p { 18 | margin: 10px; 19 | padding: 0; 20 | font-size: 1rem; 21 | font-weight: 400; 22 | } 23 | form { 24 | display: flex; 25 | flex-direction: row; 26 | align-items: center; 27 | justify-content: center; 28 | width: auto; 29 | height: 100%; 30 | } 31 | 32 | form input { 33 | width: 80%; 34 | height: 100%; 35 | border: 1px solid #ccc; 36 | outline: none; 37 | padding: 10px; 38 | font-size: 1.1rem; 39 | border-radius: 5px; 40 | margin: 0 10px; 41 | } 42 | 43 | .btn-enroll { 44 | background-color: #4caf50; 45 | color: #fff; 46 | } 47 | 48 | button { 49 | } 50 | .add-btn { 51 | background-color: #4caf50; 52 | color: #fff; 53 | width: 100px; 54 | height: 40px; 55 | border: none; 56 | outline: none; 57 | border-radius: 5px; 58 | font-size: 1.1rem; 59 | cursor: pointer; 60 | width: 70%; 61 | } 62 | a { 63 | text-decoration: none; 64 | color: white; 65 | padding: 5px; 66 | border-radius: 5px; 67 | background-color: red; 68 | padding: 10px; 69 | margin: 10px; 70 | } 71 | 72 | a:hover { 73 | transform: scale(1.1); 74 | transition: all 0.3s ease-in-out; 75 | } 76 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/components/NotesList.css: -------------------------------------------------------------------------------- 1 | .item-container { 2 | display: flex; 3 | flex-direction: row; 4 | justify-content: center; 5 | width: 100%; 6 | align-items: center; 7 | padding: 10px; 8 | } 9 | 10 | .item-content { 11 | width: 800px; 12 | padding: 10px; 13 | background-color: white; 14 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 15 | } 16 | 17 | .item-content button { 18 | width: 100%; 19 | height: 40px; 20 | border: none; 21 | outline: none; 22 | border-radius: 5px; 23 | font-size: 1.1rem; 24 | cursor: pointer; 25 | background-color: #4caf50; 26 | color: #fff; 27 | } 28 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/components/NotesList.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | import { 4 | deleteNoteAction, 5 | fetchNotesAction, 6 | } from "../redux/actions/notesAction"; 7 | 8 | import "./NotesList.css"; 9 | 10 | const NotesList = () => { 11 | //dispatch 12 | const dispatch = useDispatch(); 13 | useEffect(() => { 14 | dispatch(fetchNotesAction()); 15 | }, []); 16 | //get data from store 17 | const notes = useSelector(storeData => { 18 | return storeData.notes; 19 | }); 20 | 21 | return ( 22 | <> 23 |

Notes List

24 | 25 | {notes.map(note => ( 26 |
27 |
28 |

{note.title}

29 |

{note.content}

30 | 33 |
34 |
35 | ))} 36 | 37 | ); 38 | }; 39 | 40 | export default NotesList; 41 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/index.css: -------------------------------------------------------------------------------- 1 | /* body { 2 | background-color: #f5f5f5; 3 | } 4 | 5 | code { 6 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 7 | monospace; 8 | } */ 9 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { Provider } from "react-redux"; 4 | import "./index.css"; 5 | import App from "./App"; 6 | 7 | import reportWebVitals from "./reportWebVitals"; 8 | import store from "./redux/store/store"; 9 | 10 | const root = ReactDOM.createRoot(document.getElementById("root")); 11 | root.render( 12 | 13 | 14 | 15 | ); 16 | 17 | // If you want to start measuring performance in your app, pass a function 18 | // to log results (for example: reportWebVitals(console.log)) 19 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 20 | reportWebVitals(); 21 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/redux/actions/notesAction.js: -------------------------------------------------------------------------------- 1 | import { ADD_NOTE, DELETE_NOTE, FETCH_NOTES } from "./notesActionTypes"; 2 | 3 | //actions 4 | //Add note action creator 5 | export const addNoteAction = note => { 6 | return { 7 | type: ADD_NOTE, 8 | payload: note, 9 | }; 10 | }; 11 | //Delete note action creator 12 | export const deleteNoteAction = id => { 13 | return { 14 | type: DELETE_NOTE, 15 | payload: id, 16 | }; 17 | }; 18 | //Fetch notes action creator 19 | export const fetchNotesAction = () => { 20 | return { 21 | type: FETCH_NOTES, 22 | }; 23 | }; 24 | //store 25 | //dispatch 26 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/redux/actions/notesActionTypes.js: -------------------------------------------------------------------------------- 1 | export const ADD_NOTE = "ADD_NOTE"; 2 | export const DELETE_NOTE = "DELETE_NOTE"; 3 | export const FETCH_NOTES = "FETCH_NOTES"; 4 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/redux/reducer/noteReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_NOTE, 3 | DELETE_NOTE, 4 | FETCH_NOTES, 5 | } from "../actions/notesActionTypes"; 6 | 7 | //Initialstate 8 | const initialstate = { 9 | notes: [], 10 | }; 11 | 12 | //note reducer 13 | const notesReducer = (state = initialstate, action) => { 14 | switch (action.type) { 15 | case ADD_NOTE: 16 | //new note 17 | const newNote = { 18 | id: Math.random(), 19 | title: action.payload.title, 20 | content: action.payload.content, 21 | }; 22 | //add note into storage 23 | const updatedNotes = [...state.notes, newNote]; 24 | localStorage.setItem("notes", JSON.stringify(updatedNotes)); 25 | return { 26 | notes: [...state.notes, newNote], 27 | }; 28 | //fetch notes 29 | case FETCH_NOTES: 30 | return { 31 | notes: JSON.parse(localStorage.getItem("notes")) 32 | ? JSON.parse(localStorage.getItem("notes")) 33 | : [], 34 | }; 35 | //Delete note 36 | case DELETE_NOTE: 37 | const filteredNotes = state.notes.filter( 38 | note => note.id !== action.payload 39 | ); 40 | //Resave to localstorage 41 | localStorage.setItem("notes", JSON.stringify(filteredNotes)); 42 | return { 43 | ...state, 44 | notes: filteredNotes, 45 | }; 46 | default: 47 | return state; 48 | } 49 | }; 50 | 51 | export default notesReducer; 52 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/redux/store/store.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "redux"; 2 | import { composeWithDevTools } from "redux-devtools-extension"; 3 | import notesReducer from "../reducer/noteReducer"; 4 | 5 | const store = createStore(notesReducer, composeWithDevTools()); 6 | 7 | export default store; 8 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-redux-notes-app-final/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.3.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "axios": "^0.27.2", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0", 12 | "react-redux": "^8.0.4", 13 | "react-scripts": "5.0.1", 14 | "redux": "^4.2.0", 15 | "redux-logger": "^3.0.6", 16 | "redux-thunk": "^2.4.1", 17 | "web-vitals": "^2.1.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": [ 27 | "react-app", 28 | "react-app/jest" 29 | ] 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "redux-devtools-extension": "^2.13.9" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-notes-app-starter/public/favicon.ico -------------------------------------------------------------------------------- /react-redux-notes-app-starter/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-notes-app-starter/public/logo192.png -------------------------------------------------------------------------------- /react-redux-notes-app-starter/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-notes-app-starter/public/logo512.png -------------------------------------------------------------------------------- /react-redux-notes-app-starter/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | import AddNotes from "./components/AddNotes"; 3 | import NotesList from "./components/NotesList"; 4 | 5 | function App() { 6 | return ( 7 |
8 | 9 | 10 |
11 | ); 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/components/AddNotes.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { useDispatch } from "react-redux"; 3 | import "./Form.css"; 4 | 5 | const AddNotes = () => { 6 | //dispatch 7 | const dispatch = useDispatch(); 8 | const [note, setNote] = useState({ 9 | title: "", 10 | content: "", 11 | }); 12 | 13 | const handleChange = (e) => { 14 | setNote({ 15 | ...note, 16 | [e.target.name]: e.target.value, 17 | }); 18 | }; 19 | 20 | const handleSubmit = (e) => { 21 | //prevent empty notes 22 | if (note.title === "" || note.content === "") { 23 | return alert("Please fill in the form"); 24 | } 25 | e.preventDefault(); 26 | }; 27 | 28 | return ( 29 |
30 |
31 |

Notes Taking App Built with React Redux

32 |

33 | This is a simple notes taking app built with React Redux. You can add 34 |

35 |
36 |
37 | 44 | 52 | 55 |
56 | Enroll in the course 57 |
58 | ); 59 | }; 60 | 61 | export default AddNotes; 62 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/components/Form.css: -------------------------------------------------------------------------------- 1 | .formContainer { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | width: 100%; 7 | padding: 20px; 8 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 9 | } 10 | h3 { 11 | margin: 0; 12 | padding: 0; 13 | font-size: 2.5rem; 14 | font-weight: bold; 15 | } 16 | 17 | p { 18 | margin: 10px; 19 | padding: 0; 20 | font-size: 1rem; 21 | font-weight: 400; 22 | } 23 | form { 24 | display: flex; 25 | flex-direction: row; 26 | align-items: center; 27 | justify-content: center; 28 | width: auto; 29 | height: 100%; 30 | } 31 | 32 | form input { 33 | width: 80%; 34 | height: 100%; 35 | border: 1px solid #ccc; 36 | outline: none; 37 | padding: 10px; 38 | font-size: 1.1rem; 39 | border-radius: 5px; 40 | margin: 0 10px; 41 | } 42 | 43 | .btn-enroll { 44 | background-color: #4caf50; 45 | color: #fff; 46 | } 47 | 48 | button { 49 | } 50 | .add-btn { 51 | background-color: #4caf50; 52 | color: #fff; 53 | width: 100px; 54 | height: 40px; 55 | border: none; 56 | outline: none; 57 | border-radius: 5px; 58 | font-size: 1.1rem; 59 | cursor: pointer; 60 | width: 70%; 61 | } 62 | a { 63 | text-decoration: none; 64 | color: white; 65 | padding: 5px; 66 | border-radius: 5px; 67 | background-color: red; 68 | padding: 10px; 69 | margin: 10px; 70 | } 71 | 72 | a:hover { 73 | transform: scale(1.1); 74 | transition: all 0.3s ease-in-out; 75 | } 76 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/components/NotesList.css: -------------------------------------------------------------------------------- 1 | .item-container { 2 | display: flex; 3 | flex-direction: row; 4 | justify-content: center; 5 | width: 100%; 6 | align-items: center; 7 | padding: 10px; 8 | } 9 | 10 | .item-content { 11 | width: 800px; 12 | padding: 10px; 13 | background-color: white; 14 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); 15 | } 16 | 17 | .item-content button { 18 | width: 100%; 19 | height: 40px; 20 | border: none; 21 | outline: none; 22 | border-radius: 5px; 23 | font-size: 1.1rem; 24 | cursor: pointer; 25 | background-color: #4caf50; 26 | color: #fff; 27 | } 28 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/components/NotesList.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | 3 | import "./NotesList.css"; 4 | 5 | const NotesList = () => { 6 | return ( 7 | <> 8 |

Notes List

9 | 10 |
11 |
12 |

some title

13 |

some content

14 | 15 |
16 |
17 | 18 | ); 19 | }; 20 | 21 | export default NotesList; 22 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/index.css: -------------------------------------------------------------------------------- 1 | /* body { 2 | background-color: #f5f5f5; 3 | } 4 | 5 | code { 6 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 7 | monospace; 8 | } */ 9 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | 6 | import reportWebVitals from "./reportWebVitals"; 7 | 8 | const root = ReactDOM.createRoot(document.getElementById("root")); 9 | root.render(); 10 | 11 | // If you want to start measuring performance in your app, pass a function 12 | // to log results (for example: reportWebVitals(console.log)) 13 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 14 | reportWebVitals(); 15 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-redux-notes-app-starter/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.3.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "axios": "^0.27.2", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0", 12 | "react-redux": "^8.0.5", 13 | "react-scripts": "5.0.1", 14 | "redux": "^4.2.0", 15 | "redux-logger": "^3.0.6", 16 | "redux-thunk": "^2.4.2", 17 | "web-vitals": "^2.1.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": [ 27 | "react-app", 28 | "react-app/jest" 29 | ] 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "redux-devtools-extension": "^2.13.9" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-posts-app-final/public/favicon.ico -------------------------------------------------------------------------------- /react-redux-posts-app-final/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-posts-app-final/public/logo192.png -------------------------------------------------------------------------------- /react-redux-posts-app-final/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-posts-app-final/public/logo512.png -------------------------------------------------------------------------------- /react-redux-posts-app-final/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | 3 | import NotesList from "./components/PostsList"; 4 | 5 | function App() { 6 | return ; 7 | } 8 | 9 | export default App; 10 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/components/Form.css: -------------------------------------------------------------------------------- 1 | .form-header { 2 | background-color: #22577a; 3 | color: #fff; 4 | padding: 10px; 5 | text-align: center; 6 | } 7 | form { 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | justify-content: center; 12 | width: 100%; 13 | height: 100%; 14 | margin: 10px; 15 | } 16 | 17 | form input { 18 | border: 1px solid #ccc; 19 | outline: none; 20 | font-size: 1.1rem; 21 | border-radius: 5px; 22 | margin: 5px; 23 | padding: 5px; 24 | } 25 | 26 | form button { 27 | border: 1px solid #ccc; 28 | outline: none; 29 | color: #fff; 30 | cursor: pointer; 31 | padding: 8px; 32 | background-color: #22577a; 33 | width: 100px; 34 | border-radius: 5px; 35 | margin: 5px; 36 | } 37 | 38 | form button:hover { 39 | background-color: #1b435e; 40 | transform: scale(1.1); 41 | transition: all 0.2s ease-in-out; 42 | } 43 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/components/Header.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: #333; 3 | color: #fff; 4 | padding: 10px; 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/components/Posts.css: -------------------------------------------------------------------------------- 1 | .posts-list { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | width: 100%; 6 | background-color: #f5f5f5; 7 | } 8 | 9 | .post-details { 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | width: 80%; 14 | margin: 10px; 15 | padding: 10px; 16 | border: 1px solid #fff; 17 | border-radius: 5px; 18 | background-color: #fff; 19 | } 20 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/components/PostsList.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | import SearchPost from "./SearchPost"; 4 | import "./Posts.css"; 5 | import { fetchPostsAction } from "../redux/actions/postActions"; 6 | 7 | const PostsList = () => { 8 | //dispatch 9 | const dispatch = useDispatch(); 10 | useEffect(() => { 11 | dispatch(fetchPostsAction()); 12 | }, []); 13 | 14 | //get data from store 15 | const { loading, error, posts, post } = useSelector(data => data); 16 | 17 | console.log(loading, error, posts, post); 18 | 19 | return ( 20 | <> 21 | 22 |
23 |

Total Posts {posts.length}

24 | {loading ? ( 25 |

Loading

26 | ) : error ? ( 27 |

28 | {error.response.status && "No Post Found"} 29 |

30 | ) : ( 31 | posts.map(post => ( 32 |
33 |

{post.title}

34 |

{post.body}

35 |
36 | )) 37 | )} 38 |
39 | 40 | ); 41 | }; 42 | 43 | export default PostsList; 44 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/components/SearchPost.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useSelector, useDispatch } from "react-redux"; 3 | import { fetchPostAction } from "../redux/actions/postActions"; 4 | 5 | import "./Form.css"; 6 | const SearchPost = () => { 7 | const dispatch = useDispatch(); 8 | //search form state 9 | const [search, setSearch] = React.useState(""); 10 | //search form submit handler 11 | const handleSubmit = e => { 12 | e.preventDefault(); 13 | if (search === "") { 14 | return alert("Please provide a value"); 15 | } 16 | dispatch(fetchPostAction(search)); 17 | }; 18 | 19 | return ( 20 |
21 |
22 |

React Redux Project

23 |

24 | This project is a simple React Redux project that fetches data with 25 | search functionality from an API 26 |

27 |
28 |
29 | setSearch(e.target.value)} 34 | /> 35 | 36 |
37 |
38 | ); 39 | }; 40 | 41 | export default SearchPost; 42 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | import { Provider } from "react-redux"; 7 | import store from "./redux/store/store"; 8 | 9 | const root = ReactDOM.createRoot(document.getElementById("root")); 10 | root.render( 11 | 12 | 13 | 14 | ); 15 | 16 | // If you want to start measuring performance in your app, pass a function 17 | // to log results (for example: reportWebVitals(console.log)) 18 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 19 | reportWebVitals(); 20 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/redux/actions/postActionTypes.js: -------------------------------------------------------------------------------- 1 | //notes action types 2 | export const FETCH_POSTS_SUCCESS = "FETCH_POSTS_SUCCESS"; 3 | export const FETCH_POSTS_FAILURE = "FETCH_POSTS_FAILURE"; 4 | export const FETCH_POSTS_REQUEST = "FETCH_POSTS_REQUEST"; 5 | 6 | export const SEARCH_POST_REQUEST = "SEARCH_POST_REQUEST"; 7 | export const SEARCH_POST_SUCCESS = "SEARCH_POST_SUCCESS"; 8 | export const SEARCH_POST_FAILURE = "SEARCH_POST_FAILURE"; 9 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/redux/actions/postActions.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { 3 | FETCH_POSTS_SUCCESS, 4 | FETCH_POSTS_FAILURE, 5 | FETCH_POSTS_REQUEST, 6 | SEARCH_POST_FAILURE, 7 | SEARCH_POST_REQUEST, 8 | SEARCH_POST_SUCCESS, 9 | } from "./postActionTypes"; 10 | const apiURL = "https://jsonplaceholder.typicode.com/posts"; 11 | //Actions Creators 12 | //1. fetch posts (request started, success, error) 13 | 14 | //request started 15 | const fetchPostsRequest = () => { 16 | return { 17 | type: FETCH_POSTS_REQUEST, 18 | }; 19 | }; 20 | 21 | //success 22 | const fetchPostsSuccess = posts => { 23 | return { 24 | type: FETCH_POSTS_SUCCESS, 25 | payload: posts, 26 | }; 27 | }; 28 | 29 | //error action creator 30 | const fetchPostsErr = error => { 31 | return { 32 | type: FETCH_POSTS_FAILURE, 33 | payload: error, 34 | }; 35 | }; 36 | 37 | //fetch posts action 38 | export const fetchPostsAction = () => { 39 | return async dispatch => { 40 | //request action 41 | dispatch(fetchPostsRequest()); 42 | try { 43 | //make http request 44 | const res = await axios.get(apiURL); 45 | //success action 46 | dispatch(fetchPostsSuccess(res.data)); 47 | } catch (error) { 48 | //error action 49 | dispatch(fetchPostsErr(error)); 50 | } 51 | }; 52 | }; 53 | 54 | //2. fetch post (request started, success, error) 55 | //request action 56 | const fetchPostRequest = () => { 57 | return { 58 | type: SEARCH_POST_REQUEST, 59 | }; 60 | }; 61 | //success 62 | const fetchPostSuccess = post => { 63 | return { 64 | type: SEARCH_POST_SUCCESS, 65 | payload: post, 66 | }; 67 | }; 68 | 69 | //error action creator 70 | const fetchPostErr = error => { 71 | return { 72 | type: SEARCH_POST_FAILURE, 73 | payload: error, 74 | }; 75 | }; 76 | 77 | //single post action 78 | export const fetchPostAction = id => { 79 | return async dispatch => { 80 | dispatch(fetchPostRequest()); 81 | try { 82 | //make http request 83 | const res = await axios.get(`${apiURL}/${id}`); 84 | //success 85 | dispatch(fetchPostSuccess(res.data)); 86 | } catch (error) { 87 | dispatch(fetchPostErr(error)); 88 | } 89 | }; 90 | }; 91 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/redux/reducers/postReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | FETCH_POSTS_SUCCESS, 3 | FETCH_POSTS_FAILURE, 4 | FETCH_POSTS_REQUEST, 5 | SEARCH_POST_FAILURE, 6 | SEARCH_POST_REQUEST, 7 | SEARCH_POST_SUCCESS, 8 | } from "../actions/postActionTypes"; 9 | 10 | //initial state 11 | const initialState = { 12 | loading: false, 13 | error: "", 14 | posts: [], 15 | post: {}, 16 | }; 17 | 18 | //reducers 19 | export const postsReducer = (state = initialState, action) => { 20 | switch (action.type) { 21 | case FETCH_POSTS_REQUEST: 22 | return { 23 | ...state, 24 | loading: true, 25 | }; 26 | //success 27 | case FETCH_POSTS_SUCCESS: 28 | return { 29 | ...state, 30 | posts: action.payload, 31 | loading: false, 32 | }; 33 | //error 34 | case FETCH_POSTS_FAILURE: 35 | return { 36 | ...state, 37 | posts: [], 38 | error: action.payload, 39 | loading: false, 40 | }; 41 | //========SEARCH SINGLE POST ======= 42 | case SEARCH_POST_REQUEST: 43 | return { 44 | ...state, 45 | loading: true, 46 | }; 47 | case SEARCH_POST_SUCCESS: 48 | return { 49 | ...state, 50 | posts: [action.payload], 51 | loading: false, 52 | }; 53 | case SEARCH_POST_FAILURE: 54 | return { 55 | ...state, 56 | posts: [], 57 | error: action.payload, 58 | loading: false, 59 | }; 60 | //return default state 61 | default: 62 | return state; 63 | } 64 | }; 65 | //store 66 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/redux/store/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from "redux"; 2 | import { composeWithDevTools } from "redux-devtools-extension"; 3 | import reduxThunk from "redux-thunk"; 4 | import { postsReducer } from "../reducers/postReducer"; 5 | 6 | //combine all middlewares 7 | const middlewares = [reduxThunk]; 8 | const middlewareEnhancers = applyMiddleware(...middlewares); 9 | const store = createStore( 10 | postsReducer, 11 | composeWithDevTools(middlewareEnhancers) 12 | ); 13 | 14 | export default store; 15 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /react-redux-posts-app-final/src/utils/apiURL.js: -------------------------------------------------------------------------------- 1 | const apiURL = "https://jsonplaceholder.typicode.com/posts"; 2 | export default apiURL; 3 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.3.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "axios": "^0.27.2", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0", 12 | "react-redux": "^8.0.4", 13 | "react-scripts": "5.0.1", 14 | "redux": "^4.2.0", 15 | "redux-logger": "^3.0.6", 16 | "redux-thunk": "^2.4.1", 17 | "web-vitals": "^2.1.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": [ 27 | "react-app", 28 | "react-app/jest" 29 | ] 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "redux-devtools-extension": "^2.13.9" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-posts-app-starter/public/favicon.ico -------------------------------------------------------------------------------- /react-redux-posts-app-starter/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-posts-app-starter/public/logo192.png -------------------------------------------------------------------------------- /react-redux-posts-app-starter/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/react-redux-posts-app-starter/public/logo512.png -------------------------------------------------------------------------------- /react-redux-posts-app-starter/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | 3 | import NotesList from "./components/PostsList"; 4 | 5 | function App() { 6 | return ; 7 | } 8 | 9 | export default App; 10 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/components/Form.css: -------------------------------------------------------------------------------- 1 | .form-header { 2 | background-color: #22577a; 3 | color: #fff; 4 | padding: 10px; 5 | text-align: center; 6 | } 7 | form { 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | justify-content: center; 12 | width: 100%; 13 | height: 100%; 14 | margin: 10px; 15 | } 16 | 17 | form input { 18 | border: 1px solid #ccc; 19 | outline: none; 20 | font-size: 1.1rem; 21 | border-radius: 5px; 22 | margin: 5px; 23 | padding: 5px; 24 | } 25 | 26 | form button { 27 | border: 1px solid #ccc; 28 | outline: none; 29 | color: #fff; 30 | cursor: pointer; 31 | padding: 8px; 32 | background-color: #22577a; 33 | width: 100px; 34 | border-radius: 5px; 35 | margin: 5px; 36 | } 37 | 38 | form button:hover { 39 | background-color: #1b435e; 40 | transform: scale(1.1); 41 | transition: all 0.2s ease-in-out; 42 | } 43 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/components/Header.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: #333; 3 | color: #fff; 4 | padding: 10px; 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/components/Posts.css: -------------------------------------------------------------------------------- 1 | .posts-list { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | width: 100%; 6 | background-color: #f5f5f5; 7 | } 8 | 9 | .post-details { 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | width: 80%; 14 | margin: 10px; 15 | padding: 10px; 16 | border: 1px solid #fff; 17 | border-radius: 5px; 18 | background-color: #fff; 19 | } 20 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/components/PostsList.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import SearchPost from "./SearchPost"; 3 | import "./Posts.css"; 4 | 5 | const PostsList = () => { 6 | return ( 7 | <> 8 | 9 |
10 |

Total Posts 100

11 |
12 |

Post Title 1

13 |

Post body 1

14 |
15 |
16 | 17 | ); 18 | }; 19 | 20 | export default PostsList; 21 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/components/SearchPost.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./Form.css"; 3 | const SearchPost = () => { 4 | //search form state 5 | const [search, setSearch] = React.useState(""); 6 | //search form submit handler 7 | const handleSubmit = e => { 8 | e.preventDefault(); 9 | }; 10 | 11 | return ( 12 |
13 |
14 |

React Redux Project

15 |

16 | This project is a simple React Redux project that fetches data with 17 | search functionality from an API 18 |

19 |
20 |
21 | setSearch(e.target.value)} 26 | /> 27 | 28 |
29 |
30 | ); 31 | }; 32 | 33 | export default SearchPost; 34 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById("root")); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-redux-posts-app-starter/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-final/.DS_Store -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@headlessui/react": "^1.7.2", 7 | "@heroicons/react": "^2.0.11", 8 | "@reduxjs/toolkit": "^1.8.5", 9 | "@testing-library/jest-dom": "^5.16.5", 10 | "@testing-library/react": "^13.3.0", 11 | "@testing-library/user-event": "^13.5.0", 12 | "axios": "^0.27.2", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "react-redux": "^8.0.4", 16 | "react-router-dom": "^6.4.1", 17 | "react-scripts": "5.0.1", 18 | "web-vitals": "^2.1.4" 19 | }, 20 | "scripts": { 21 | "start": "react-scripts start", 22 | "build": "react-scripts build", 23 | "test": "react-scripts test", 24 | "eject": "react-scripts eject" 25 | }, 26 | "eslintConfig": { 27 | "extends": [ 28 | "react-app", 29 | "react-app/jest" 30 | ] 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | }, 44 | "devDependencies": { 45 | "autoprefixer": "^10.4.12", 46 | "postcss": "^8.4.16", 47 | "tailwindcss": "^3.1.8" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-final/public/favicon.ico -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-final/public/logo192.png -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-final/public/logo512.png -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/App.js: -------------------------------------------------------------------------------- 1 | import Home from "./components/HomePage/Home"; 2 | import Register from "./components/Forms/Register"; 3 | import MainDashBoard from "./components/Dashboard/MainDashBoard"; 4 | import AccountDetails from "./components/Dashboard/AccountDetails"; 5 | import Navbar from "./components/Navbar/Navbar"; 6 | import { BrowserRouter, Routes, Route } from "react-router-dom"; 7 | import AddTransaction from "./components/Forms/AddTransaction"; 8 | import EditTransaction from "./components/Forms/EditTransaction"; 9 | import AddAccount from "./components/Forms/AddAccount"; 10 | import EditAccount from "./components/Forms/EditAccount"; 11 | import Login from "./components/Forms/Login"; 12 | import AuthRoute from "./components/AuthRoute/AuthRoute"; 13 | 14 | function App() { 15 | return ( 16 | 17 | 18 | 19 | } /> 20 | } /> 21 | 25 | 26 | 27 | } 28 | /> 29 | 30 | 34 | 35 | 36 | } 37 | /> 38 | 39 | 43 | 44 | 45 | } 46 | /> 47 | 48 | 52 | 53 | 54 | } 55 | /> 56 | 60 | 61 | 62 | } 63 | /> 64 | 68 | 69 | 70 | } 71 | /> 72 | } /> 73 | 74 | 75 | ); 76 | } 77 | 78 | export default App; 79 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-final/src/assets/logo.png -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/components/AuthRoute/AuthRoute.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useSelector } from "react-redux"; 3 | 4 | const AuthRoute = ({ children }) => { 5 | //get token from store 6 | const { userInfo } = useSelector((state) => state?.users?.userAuth); 7 | if (!userInfo?.token) { 8 | window.location.href = "/login"; 9 | return null; 10 | } 11 | return
{children}
; 12 | }; 13 | 14 | export default AuthRoute; 15 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/components/Dashboard/AccountSummary.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const AccountSummary = ({ profile }) => { 4 | //get all accounts 5 | const accounts = profile?.accounts; 6 | 7 | //get all transactions 8 | const transactions = accounts?.map((account) => account?.transactions); 9 | console.log(transactions); 10 | //total income 11 | const totalIncome = transactions?.reduce((acc, transaction) => { 12 | return ( 13 | acc + 14 | transaction 15 | ?.filter((transaction) => transaction?.transactionType === "Income") 16 | .reduce((acc, transaction) => acc + transaction?.amount, 0) 17 | ); 18 | }, 0); 19 | 20 | //total expenses 21 | const totalExpenses = transactions?.reduce((acc, transaction) => { 22 | return ( 23 | acc + 24 | transaction 25 | ?.filter((transaction) => transaction?.transactionType === "Expenses") 26 | .reduce((acc, transaction) => acc + transaction?.amount, 0) 27 | ); 28 | }, 0); 29 | 30 | console.log(totalExpenses); 31 | return ( 32 | <> 33 | {profile?.accounts?.length <= 0 ? ( 34 |

No Account Summary Found

35 | ) : ( 36 |
37 |

38 | Account Summary - for {profile?.accounts?.length} accounts 39 |

40 |
41 |
42 |
43 |

Total Income

44 | 45 | $ {totalIncome} 46 | 47 |
48 |
49 |

Total Expenses

50 | 51 | $ {totalExpenses} 52 | 53 |
54 |
55 |

Total Balance

56 | 57 | $ {totalIncome - totalExpenses} 58 | 59 |
60 |
61 |

Total Transactions

62 | 63 | {transactions?.length} 64 | 65 |
66 |
67 |
68 |
69 | )} 70 | 71 | ); 72 | }; 73 | 74 | export default AccountSummary; 75 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/components/Dashboard/MainDashBoard.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useSelector, useDispatch } from "react-redux"; 3 | import { getProfileAction } from "../../redux/slice/users/usersSlice"; 4 | 5 | import AccountList from "./AccountList"; 6 | import AccountSummary from "./AccountSummary"; 7 | 8 | const MainDashBoard = () => { 9 | //dispatch 10 | const dispatch = useDispatch(); 11 | 12 | useEffect(() => { 13 | dispatch(getProfileAction()); 14 | }, [dispatch]); 15 | //get data from store 16 | const { profile, error, loading } = useSelector((state) => state?.users); 17 | 18 | return ( 19 | <> 20 | {loading ? ( 21 |

Loading...

22 | ) : error ? ( 23 |

{error}

24 | ) : ( 25 | <> 26 | 27 | 28 | 29 | )} 30 | 31 | ); 32 | }; 33 | 34 | export default MainDashBoard; 35 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { Provider } from "react-redux"; 4 | 5 | import "./index.css"; 6 | import App from "./App"; 7 | import reportWebVitals from "./reportWebVitals"; 8 | import store from "./redux/store/store"; 9 | 10 | const root = ReactDOM.createRoot(document.getElementById("root")); 11 | root.render( 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | 19 | // If you want to start measuring performance in your app, pass a function 20 | // to log results (for example: reportWebVitals(console.log)) 21 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 22 | reportWebVitals(); 23 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/redux/store/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import accountsReducer from "../slice/accounts/accountsSlice"; 3 | import transactionsReducer from "../slice/transactions/transactionSlice"; 4 | import usersReducer from "../slice/users/usersSlice"; 5 | 6 | //store 7 | const store = configureStore({ 8 | reducer: { 9 | users: usersReducer, 10 | accounts: accountsReducer, 11 | transactions: transactionsReducer, 12 | }, 13 | }); 14 | 15 | export default store; 16 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/src/utils/baseURL.js: -------------------------------------------------------------------------------- 1 | const baseURL = "https://income-expenses-tracker-web-dev.onrender.com/api/v1"; 2 | 3 | export default baseURL; 4 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-final/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{js,jsx,ts,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-starter/.DS_Store -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@headlessui/react": "^1.7.2", 7 | "@heroicons/react": "^2.0.11", 8 | "@reduxjs/toolkit": "^1.8.5", 9 | "@testing-library/jest-dom": "^5.16.5", 10 | "@testing-library/react": "^13.3.0", 11 | "@testing-library/user-event": "^13.5.0", 12 | "axios": "^0.27.2", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "react-redux": "^8.0.4", 16 | "react-router-dom": "^6.4.1", 17 | "react-scripts": "5.0.1", 18 | "web-vitals": "^2.1.4" 19 | }, 20 | "scripts": { 21 | "start": "react-scripts start", 22 | "build": "react-scripts build", 23 | "test": "react-scripts test", 24 | "eject": "react-scripts eject" 25 | }, 26 | "eslintConfig": { 27 | "extends": [ 28 | "react-app", 29 | "react-app/jest" 30 | ] 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | }, 44 | "devDependencies": { 45 | "autoprefixer": "^10.4.12", 46 | "postcss": "^8.4.16", 47 | "tailwindcss": "^3.1.8" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-starter/public/favicon.ico -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-starter/public/logo192.png -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-starter/public/logo512.png -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/App.js: -------------------------------------------------------------------------------- 1 | import Home from "./components/HomePage/Home"; 2 | import Register from "./components/Forms/Register"; 3 | import MainDashBoard from "./components/Dashboard/MainDashBoard"; 4 | import AccountDetails from "./components/Dashboard/AccountDetails"; 5 | import Navbar from "./components/Navbar/Navbar"; 6 | import { BrowserRouter, Routes, Route } from "react-router-dom"; 7 | import AddTransaction from "./components/Forms/AddTransaction"; 8 | import EditTransaction from "./components/Forms/EditTransaction"; 9 | import AddAccount from "./components/Forms/AddAccount"; 10 | import EditAccount from "./components/Forms/EditAccount"; 11 | import Login from "./components/Forms/Login"; 12 | 13 | function App() { 14 | return ( 15 | 16 | 17 | 18 | } /> 19 | } /> 20 | } /> 21 | } /> 22 | } /> 23 | } /> 24 | } /> 25 | } /> 26 | } /> 27 | } /> 28 | 29 | 30 | ); 31 | } 32 | 33 | export default App; 34 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-income-expenses-project-starter/src/assets/logo.png -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/components/Dashboard/AccountSummary.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const AccountSummary = () => { 4 | return ( 5 |
6 |

Account Summary

7 |
8 |
9 |
10 |

Total Revenue

11 | $33,261 12 |
13 |
14 |

Subscribers

15 | 481,095 16 |
17 |
18 |

Conversations

19 | 643,533 20 |
21 |
22 |

Modal Sale Rate

23 | 25% 24 |
25 |
26 |
27 |
28 | ); 29 | }; 30 | 31 | export default AccountSummary; 32 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/components/Dashboard/MainDashBoard.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import AccountList from "./AccountList"; 3 | import AccountSummary from "./AccountSummary"; 4 | 5 | const MainDashBoard = () => { 6 | return ( 7 | <> 8 | 9 | 10 | 11 | ); 12 | }; 13 | 14 | export default MainDashBoard; 15 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/components/Forms/Login.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | const Login = () => { 5 | const [formData, setFormData] = useState({ 6 | email: "", 7 | password: "", 8 | }); 9 | //---Destructuring--- 10 | const { email, password } = formData; 11 | //---onchange handler---- 12 | const onChangeHandler = (e) => { 13 | setFormData({ ...formData, [e.target.name]: e.target.value }); 14 | }; 15 | 16 | //---onsubmit handler---- 17 | const onSubmitHandler = (e) => { 18 | e.preventDefault(); 19 | console.log(formData); 20 | }; 21 | return ( 22 | <> 23 |
24 |
25 |
26 |
27 |
28 |

29 | Login 30 |

31 |
32 |
33 |
34 | 37 | 45 |
46 |
47 | 50 | 58 |
59 |
60 | 66 |
67 | 71 | Register Instead 72 | 73 |
74 |
75 |
76 |
77 | 78 | ); 79 | }; 80 | 81 | export default Login; 82 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /rtk-income-expenses-project-starter/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{js,jsx,ts,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /rtk-posts-app-final/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /rtk-posts-app-final/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@reduxjs/toolkit": "^1.9.0", 7 | "@testing-library/jest-dom": "^5.16.5", 8 | "@testing-library/react": "^13.3.0", 9 | "@testing-library/user-event": "^13.5.0", 10 | "axios": "^0.27.2", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0", 13 | "react-redux": "^8.0.5", 14 | "react-scripts": "5.0.1", 15 | "web-vitals": "^2.1.4" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | }, 41 | "devDependencies": { 42 | "redux-devtools-extension": "^2.13.9" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /rtk-posts-app-final/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-posts-app-final/public/favicon.ico -------------------------------------------------------------------------------- /rtk-posts-app-final/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /rtk-posts-app-final/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-posts-app-final/public/logo192.png -------------------------------------------------------------------------------- /rtk-posts-app-final/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweneboah/redux-core-react-redux-redux-toolkit-course/9d8f98dd3a422d73b2479a9a6a62a73cf9a363c4/rtk-posts-app-final/public/logo512.png -------------------------------------------------------------------------------- /rtk-posts-app-final/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /rtk-posts-app-final/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | 3 | import NotesList from "./components/PostsList"; 4 | 5 | function App() { 6 | return ; 7 | } 8 | 9 | export default App; 10 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/components/Form.css: -------------------------------------------------------------------------------- 1 | .form-header { 2 | background-color: #22577a; 3 | color: #fff; 4 | padding: 10px; 5 | text-align: center; 6 | } 7 | form { 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | justify-content: center; 12 | width: 100%; 13 | height: 100%; 14 | margin: 10px; 15 | } 16 | 17 | form input { 18 | border: 1px solid #ccc; 19 | outline: none; 20 | font-size: 1.1rem; 21 | border-radius: 5px; 22 | margin: 5px; 23 | padding: 5px; 24 | } 25 | 26 | form button { 27 | border: 1px solid #ccc; 28 | outline: none; 29 | color: #fff; 30 | cursor: pointer; 31 | padding: 8px; 32 | background-color: #22577a; 33 | width: 100px; 34 | border-radius: 5px; 35 | margin: 5px; 36 | } 37 | 38 | form button:hover { 39 | background-color: #1b435e; 40 | transform: scale(1.1); 41 | transition: all 0.2s ease-in-out; 42 | } 43 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/components/Header.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: #333; 3 | color: #fff; 4 | padding: 10px; 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/components/Posts.css: -------------------------------------------------------------------------------- 1 | .posts-list { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | width: 100%; 6 | background-color: #f5f5f5; 7 | } 8 | 9 | .post-details { 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | width: 80%; 14 | margin: 10px; 15 | padding: 10px; 16 | border: 1px solid #fff; 17 | border-radius: 5px; 18 | background-color: #fff; 19 | } 20 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/components/PostsList.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | import SearchPost from "./SearchPost"; 4 | import "./Posts.css"; 5 | import { fetchPosts } from "../redux/slice/postsSlice"; 6 | 7 | const PostsList = () => { 8 | //dispatch 9 | const dispatch = useDispatch(); 10 | useEffect(() => { 11 | dispatch(fetchPosts(100)); 12 | }, []); 13 | //Get data from store 14 | const { posts, loading, error } = useSelector((state) => { 15 | return state.posts; 16 | }); 17 | return ( 18 | <> 19 | 20 |
21 |

Total Posts {posts.length}

22 | {loading ? ( 23 |

Loading...

24 | ) : error ? ( 25 |

{error}

26 | ) : ( 27 | posts.map((post) => { 28 | return ( 29 |
30 |

{post.title}

31 |

{post.body}

32 |
33 | ); 34 | }) 35 | )} 36 |
37 | 38 | ); 39 | }; 40 | 41 | export default PostsList; 42 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/components/SearchPost.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | import { searchPost } from "../redux/slice/postsSlice"; 4 | import "./Form.css"; 5 | 6 | const SearchPost = () => { 7 | const dispatch = useDispatch(); 8 | //search form state 9 | const [search, setSearch] = React.useState(""); 10 | //search form submit handler 11 | const handleSubmit = (e) => { 12 | e.preventDefault(); 13 | dispatch(searchPost(search)); 14 | }; 15 | 16 | return ( 17 |
18 |
19 |

React Redux Project

20 |

21 | This project is a simple React Redux project that fetches data with 22 | search functionality from an API 23 |

24 |
25 |
26 | setSearch(e.target.value)} 31 | /> 32 | 33 |
34 |
35 | ); 36 | }; 37 | 38 | export default SearchPost; 39 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | } 7 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { Provider } from "react-redux"; 4 | import "./index.css"; 5 | import App from "./App"; 6 | import reportWebVitals from "./reportWebVitals"; 7 | import store from "./redux/store/store"; 8 | 9 | const root = ReactDOM.createRoot(document.getElementById("root")); 10 | root.render( 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | 18 | // If you want to start measuring performance in your app, pass a function 19 | // to log results (for example: reportWebVitals(console.log)) 20 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 21 | reportWebVitals(); 22 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/redux/slice/postsSlice.js: -------------------------------------------------------------------------------- 1 | import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; 2 | import axios from "axios"; 3 | import apiURL from "../../utils/apiURL"; 4 | 5 | //initialState 6 | const initialState = { 7 | posts: [], 8 | loading: false, 9 | error: "", 10 | }; 11 | 12 | //actions for fetch all posts 13 | export const fetchPosts = createAsyncThunk( 14 | "posts/fetch", 15 | async (payload, { rejectWithValue, getState, dispatch }) => { 16 | try { 17 | const res = await axios.get(apiURL); 18 | return res.data; 19 | } catch (error) { 20 | console.log(error); 21 | return rejectWithValue(error.response.status); 22 | } 23 | } 24 | ); 25 | 26 | //Search post Action 27 | export const searchPost = createAsyncThunk( 28 | "posts/search", 29 | async (id, { rejectWithValue, getState, dispatch }) => { 30 | try { 31 | const res = await axios.get(`${apiURL}/${id}`); 32 | return res.data; 33 | } catch (error) { 34 | console.log(error); 35 | return rejectWithValue(error.response.status); 36 | } 37 | } 38 | ); 39 | //slice 40 | const postsSlice = createSlice({ 41 | name: "posts", 42 | initialState, 43 | extraReducers: (builder) => { 44 | //handle actions 45 | //pending 46 | builder.addCase(fetchPosts.pending, (state, action) => { 47 | state.loading = true; 48 | }); 49 | //fulfilled 50 | builder.addCase(fetchPosts.fulfilled, (state, action) => { 51 | state.loading = false; 52 | state.posts = action.payload; 53 | }); 54 | //Rejected 55 | builder.addCase(fetchPosts.rejected, (state, action) => { 56 | state.loading = false; 57 | state.posts = []; 58 | state.error = action.payload; 59 | }); 60 | //search post 61 | builder.addCase(searchPost.pending, (state, action) => { 62 | state.loading = true; 63 | }); 64 | builder.addCase(searchPost.fulfilled, (state, action) => { 65 | state.loading = false; 66 | state.posts = [action.payload]; 67 | }); 68 | builder.addCase(searchPost.rejected, (state, action) => { 69 | state.loading = false; 70 | state.posts = []; 71 | state.error = action.payload; 72 | }); 73 | }, 74 | }); 75 | 76 | //Generate reducer 77 | const postsReducer = postsSlice.reducer; 78 | 79 | export default postsReducer; 80 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/redux/store/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import postsReducer from "../slice/postsSlice"; 3 | 4 | //store 5 | 6 | const store = configureStore({ 7 | reducer: { 8 | posts: postsReducer, 9 | }, 10 | }); 11 | 12 | export default store; 13 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /rtk-posts-app-final/src/utils/apiURL.js: -------------------------------------------------------------------------------- 1 | const apiUrl = "https://jsonplaceholder.typicode.com/posts"; 2 | export default apiUrl; 3 | --------------------------------------------------------------------------------