├── .gitignore ├── 1-react-state-management └── 11-how-react-manage-state │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── index.js │ └── setupTests.js │ └── yarn.lock ├── 10-react-query ├── 101-react-custom-usequery │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── repositories │ │ └── DataRepository.js │ │ ├── setupTests.js │ │ └── useQuery.js ├── 102-react-usequery │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ ├── tests │ │ │ └── ProductList.test.js │ │ └── useProdutcs.js │ │ ├── productsContext.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── reducer.js │ │ ├── repositories │ │ └── CartRepository.js │ │ ├── tests │ │ └── Cart.test.js │ │ └── useShoppingCart.js └── 103-react-usequery-advanced │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ └── src │ ├── index.js │ ├── products │ ├── components │ │ └── ProductList.js │ ├── index.js │ ├── repositories │ │ └── ProductsRepository.js │ ├── tests │ │ └── ProductList.test.js │ └── useProdutcs.js │ ├── productsContext.js │ ├── setupTests.js │ └── shoppingcart │ ├── components │ └── ShoppingCart.js │ ├── index.js │ ├── reducer.js │ ├── repositories │ └── CartRepository.js │ ├── tests │ └── Cart.test.js │ └── useShoppingCart.js ├── 11-state-management-alternatives ├── 111-recoil │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ ├── state │ │ │ └── atoms.js │ │ └── tests │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── repositories │ │ └── CartRepository.js │ │ ├── state │ │ └── atoms.js │ │ └── tests │ │ └── Cart.test.js ├── 112-xstate │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ ├── tests │ │ │ └── ProductList.test.js │ │ └── useProdutcs.js │ │ ├── productsContext.js │ │ ├── setupTests.js │ │ ├── shoppingcart │ │ ├── components │ │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── reducer.js │ │ ├── repositories │ │ │ └── CartRepository.js │ │ ├── tests │ │ │ └── Cart.test.js │ │ └── useShoppingCart.js │ │ └── useToggle.js ├── 113-jotai │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ ├── state │ │ │ └── atoms.js │ │ └── tests │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── repositories │ │ └── CartRepository.js │ │ ├── state │ │ └── atoms.js │ │ └── tests │ │ └── Cart.test.js ├── 113-valtio │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ ├── state │ │ │ └── index.js │ │ └── tests │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ ├── shoppingcart │ │ ├── components │ │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── CartRepository.js │ │ ├── state │ │ │ └── index.js │ │ └── tests │ │ │ └── Cart.test.js │ │ └── state.js └── 113-zustand │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── config │ │ └── store.js │ ├── index.js │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ └── tests │ │ │ └── ProductList.test.js │ ├── setupTests.js │ └── shoppingcart │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── repositories │ │ └── CartRepository.js │ │ └── tests │ │ └── Cart.test.js │ └── yarn.lock ├── 12-extra └── 121-redux-toolkit-typescript │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── config │ │ └── store.ts │ ├── index.tsx │ ├── products │ │ ├── components │ │ │ └── ProductList.tsx │ │ ├── index.tsx │ │ ├── product.ts │ │ ├── repositories │ │ │ └── ProductsRepository.ts │ │ ├── slices │ │ │ └── index.ts │ │ └── tests │ │ │ └── ProductList.test.js │ ├── react-app-env.d.ts │ ├── setupTests.js │ └── shoppingcart │ │ ├── cartProduct.ts │ │ ├── components │ │ └── ShoppingCart.tsx │ │ ├── index.tsx │ │ ├── repositories │ │ └── CartRepository.ts │ │ ├── slices │ │ └── index.ts │ │ └── tests │ │ └── Cart.test.js │ ├── tsconfig.json │ └── yarn.lock ├── 2-unidirectional-data-flow ├── 22-when-to-use-redux │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── config │ │ │ └── store.js │ │ ├── index.js │ │ ├── products │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── components │ │ │ │ └── ProductList.js │ │ │ ├── constants │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ │ └── index.js │ │ │ ├── repositories │ │ │ │ └── ProductsRepository.js │ │ │ └── tests │ │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ │ ├── actions │ │ │ └── index.js │ │ │ ├── components │ │ │ └── ShoppingCart.js │ │ │ ├── constants │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ └── index.js │ │ │ ├── repositories │ │ │ └── CartRepository.js │ │ │ └── tests │ │ │ └── Cart.test.js │ └── yarn.lock └── 23-checking-functional-patterns-by-test │ ├── babel.config.js │ ├── package-lock.json │ ├── package.json │ └── test │ ├── 1-declarative-mutations.test.js │ └── 2-reducer-immutable.test.js ├── 3-redux-first-steps ├── 31-redux-store-by-test │ ├── babel.config.js │ ├── package-lock.json │ ├── package.json │ └── test │ │ ├── 1-store-standalone.test.js │ │ ├── 2-redux-react-without-connect.test.js │ │ └── 3-redux-react.test.js ├── 32-redux-shopping-cart │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── config │ │ │ └── store.js │ │ ├── index.js │ │ ├── products │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── components │ │ │ │ └── ProductList.js │ │ │ ├── constants │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ │ └── index.js │ │ │ ├── repositories │ │ │ │ └── ProductsRepository.js │ │ │ └── tests │ │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ │ ├── actions │ │ │ └── index.js │ │ │ ├── components │ │ │ └── ShoppingCart.js │ │ │ ├── constants │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ └── index.js │ │ │ ├── repositories │ │ │ └── CartRepository.js │ │ │ └── tests │ │ │ └── Cart.test.js │ └── yarn.lock ├── 33-redux-shopping-cart-with-thunk │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── config │ │ │ └── store.js │ │ ├── index.js │ │ ├── products │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── components │ │ │ │ └── ProductList.js │ │ │ ├── constants │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ │ └── index.js │ │ │ ├── repositories │ │ │ │ └── ProductsRepository.js │ │ │ └── tests │ │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ │ ├── actions │ │ │ └── index.js │ │ │ ├── components │ │ │ └── ShoppingCart.js │ │ │ ├── constants │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ └── index.js │ │ │ ├── repositories │ │ │ └── CartRepository.js │ │ │ └── tests │ │ │ └── Cart.test.js │ └── yarn.lock └── 34-redux-dev-tools │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── config │ │ └── store.js │ ├── index.js │ ├── products │ │ ├── actions │ │ │ └── index.js │ │ ├── components │ │ │ └── ProductList.js │ │ ├── constants │ │ │ └── index.js │ │ ├── index.js │ │ ├── reducers │ │ │ └── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ └── tests │ │ │ └── ProductList.test.js │ ├── setupTests.js │ └── shoppingcart │ │ ├── actions │ │ └── index.js │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── constants │ │ └── index.js │ │ ├── index.js │ │ ├── reducers │ │ └── index.js │ │ ├── repositories │ │ └── CartRepository.js │ │ └── tests │ │ └── Cart.test.js │ └── yarn.lock ├── 4-redux-problems-and-solutions ├── 42-redux-immer │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── config │ │ │ └── store.js │ │ ├── index.js │ │ ├── products │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── components │ │ │ │ └── ProductList.js │ │ │ ├── constants │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ │ └── index.js │ │ │ ├── repositories │ │ │ │ └── ProductsRepository.js │ │ │ └── tests │ │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ │ ├── actions │ │ │ └── index.js │ │ │ ├── components │ │ │ └── ShoppingCart.js │ │ │ ├── constants │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ └── index.js │ │ │ ├── repositories │ │ │ └── CartRepository.js │ │ │ └── tests │ │ │ └── Cart.test.js │ └── yarn.lock └── 43-redux-performance-improvements │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── config │ │ └── store.js │ ├── index.js │ ├── products │ │ ├── actions │ │ │ └── index.js │ │ ├── components │ │ │ └── ProductList.js │ │ ├── constants │ │ │ └── index.js │ │ ├── index.js │ │ ├── reducers │ │ │ └── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ └── tests │ │ │ └── ProductList.test.js │ ├── setupTests.js │ └── shoppingcart │ │ ├── actions │ │ └── index.js │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── constants │ │ └── index.js │ │ ├── index.js │ │ ├── reducers │ │ └── index.js │ │ ├── repositories │ │ └── CartRepository.js │ │ └── tests │ │ └── Cart.test.js │ └── yarn.lock ├── 5-redux-toolkit ├── 51-redux-toolkit-config │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── config │ │ │ └── store.js │ │ ├── index.js │ │ ├── products │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── components │ │ │ │ └── ProductList.js │ │ │ ├── constants │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ │ └── index.js │ │ │ ├── repositories │ │ │ │ └── ProductsRepository.js │ │ │ └── tests │ │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ │ ├── actions │ │ │ └── index.js │ │ │ ├── components │ │ │ └── ShoppingCart.js │ │ │ ├── constants │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ └── index.js │ │ │ ├── repositories │ │ │ └── CartRepository.js │ │ │ └── tests │ │ │ └── Cart.test.js │ └── yarn.lock ├── 52-redux-toolkit-slice │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── config │ │ │ └── store.js │ │ ├── index.js │ │ ├── products │ │ │ ├── components │ │ │ │ └── ProductList.js │ │ │ ├── index.js │ │ │ ├── repositories │ │ │ │ └── ProductsRepository.js │ │ │ ├── slices │ │ │ │ └── index.js │ │ │ └── tests │ │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ │ ├── actions │ │ │ └── index.js │ │ │ ├── components │ │ │ └── ShoppingCart.js │ │ │ ├── index.js │ │ │ ├── repositories │ │ │ └── CartRepository.js │ │ │ ├── slices │ │ │ └── index.js │ │ │ └── tests │ │ │ └── Cart.test.js │ └── yarn.lock └── 53-redux-toolkit-connect-components │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── config │ │ └── store.js │ ├── index.js │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ ├── slices │ │ │ └── index.js │ │ └── tests │ │ │ └── ProductList.test.js │ ├── setupTests.js │ └── shoppingcart │ │ ├── actions │ │ └── index.js │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── repositories │ │ └── CartRepository.js │ │ ├── slices │ │ └── index.js │ │ └── tests │ │ └── Cart.test.js │ └── yarn.lock ├── 6-redux-toolkit-other-patterns ├── 61-redux-toolkit-thunk │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── config │ │ │ └── store.js │ │ ├── index.js │ │ ├── products │ │ │ ├── components │ │ │ │ └── ProductList.js │ │ │ ├── index.js │ │ │ ├── repositories │ │ │ │ └── ProductsRepository.js │ │ │ ├── slices │ │ │ │ └── index.js │ │ │ └── tests │ │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ │ ├── actions │ │ │ └── index.js │ │ │ ├── components │ │ │ └── ShoppingCart.js │ │ │ ├── index.js │ │ │ ├── repositories │ │ │ └── CartRepository.js │ │ │ ├── slices │ │ │ └── index.js │ │ │ └── tests │ │ │ └── Cart.test.js │ └── yarn.lock └── 62-redux-toolkit-entity-adapter │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── config │ │ └── store.js │ ├── index.js │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ ├── slices │ │ │ └── index.js │ │ └── tests │ │ │ └── ProductList.test.js │ ├── setupTests.js │ └── shoppingcart │ │ ├── actions │ │ └── index.js │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── repositories │ │ └── CartRepository.js │ │ ├── slices │ │ └── index.js │ │ └── tests │ │ └── Cart.test.js │ └── yarn.lock ├── 8-react-hooks ├── 81-react-useState │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ └── tests │ │ │ └── ProductList.test.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── repositories │ │ └── CartRepository.js │ │ └── tests │ │ └── Cart.test.js ├── 82-react-useReducer │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ └── tests │ │ │ └── ProductList.test.js │ │ ├── reducer.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── repositories │ │ └── CartRepository.js │ │ └── tests │ │ └── Cart.test.js └── 83-react-custom-hook │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ └── src │ ├── index.js │ ├── products │ ├── components │ │ └── ProductList.js │ ├── index.js │ ├── repositories │ │ └── ProductsRepository.js │ ├── tests │ │ └── ProductList.test.js │ └── useProdutcs.js │ ├── setupTests.js │ └── shoppingcart │ ├── components │ └── ShoppingCart.js │ ├── index.js │ ├── reducer.js │ ├── repositories │ └── CartRepository.js │ ├── tests │ └── Cart.test.js │ └── useShoppingCart.js ├── 9-react-context ├── 91-react-context-foundations │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ ├── tests │ │ │ └── ProductList.test.js │ │ └── useProdutcs.js │ │ ├── productsContext.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── reducer.js │ │ ├── repositories │ │ └── CartRepository.js │ │ ├── tests │ │ └── Cart.test.js │ │ └── useShoppingCart.js ├── 92-react-useContext │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── index.js │ │ ├── products │ │ ├── components │ │ │ └── ProductList.js │ │ ├── index.js │ │ ├── repositories │ │ │ └── ProductsRepository.js │ │ ├── tests │ │ │ └── ProductList.test.js │ │ └── useProdutcs.js │ │ ├── productsContext.js │ │ ├── setupTests.js │ │ └── shoppingcart │ │ ├── components │ │ └── ShoppingCart.js │ │ ├── index.js │ │ ├── reducer.js │ │ ├── repositories │ │ └── CartRepository.js │ │ ├── tests │ │ └── Cart.test.js │ │ └── useShoppingCart.js └── 93-react-composition │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ └── src │ ├── UserInfo.js │ ├── index.js │ ├── products │ ├── components │ │ └── ProductList.js │ ├── index.js │ ├── repositories │ │ └── ProductsRepository.js │ ├── tests │ │ └── ProductList.test.js │ └── useProdutcs.js │ ├── productsContext.js │ ├── setupTests.js │ └── shoppingcart │ ├── components │ └── ShoppingCart.js │ ├── index.js │ ├── reducer.js │ ├── repositories │ └── CartRepository.js │ ├── tests │ └── Cart.test.js │ └── useShoppingCart.js └── readme.md /.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 | -------------------------------------------------------------------------------- /1-react-state-management/11-how-react-manage-state/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /1-react-state-management/11-how-react-manage-state/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/1-react-state-management/11-how-react-manage-state/public/favicon.ico -------------------------------------------------------------------------------- /1-react-state-management/11-how-react-manage-state/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/1-react-state-management/11-how-react-manage-state/public/logo192.png -------------------------------------------------------------------------------- /1-react-state-management/11-how-react-manage-state/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/1-react-state-management/11-how-react-manage-state/public/logo512.png -------------------------------------------------------------------------------- /1-react-state-management/11-how-react-manage-state/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 | -------------------------------------------------------------------------------- /1-react-state-management/11-how-react-manage-state/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /1-react-state-management/11-how-react-manage-state/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 | -------------------------------------------------------------------------------- /10-react-query/101-react-custom-usequery/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/10-react-query/101-react-custom-usequery/public/favicon.ico -------------------------------------------------------------------------------- /10-react-query/101-react-custom-usequery/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/10-react-query/101-react-custom-usequery/public/logo192.png -------------------------------------------------------------------------------- /10-react-query/101-react-custom-usequery/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/10-react-query/101-react-custom-usequery/public/logo512.png -------------------------------------------------------------------------------- /10-react-query/101-react-custom-usequery/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 | -------------------------------------------------------------------------------- /10-react-query/101-react-custom-usequery/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /10-react-query/101-react-custom-usequery/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | 4 | import { retrieveData } from "./repositories/DataRepository"; 5 | import { useQuery } from "./useQuery"; 6 | 7 | const App = () => { 8 | const { data, isLoading } = useQuery(retrieveData); 9 | 10 | if (isLoading) { 11 | return Loading... 12 | } 13 | 14 | return ( 15 | <> 16 |

ToDo list

17 | 22 | 23 | ); 24 | }; 25 | 26 | render( 27 | , 28 | document.getElementById("root") 29 | ); 30 | -------------------------------------------------------------------------------- /10-react-query/101-react-custom-usequery/src/repositories/DataRepository.js: -------------------------------------------------------------------------------- 1 | export async function retrieveData() { 2 | const response = await fetch("https://jsonplaceholder.typicode.com/todos"); 3 | const data = await response.json(); 4 | return data; 5 | } -------------------------------------------------------------------------------- /10-react-query/101-react-custom-usequery/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 | -------------------------------------------------------------------------------- /10-react-query/101-react-custom-usequery/src/useQuery.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | export function useQuery(retrieveData) { 4 | const [data, setData] = useState([]); 5 | const [isLoading, setIsLoading] = useState(false); 6 | 7 | useEffect(() => { 8 | setIsLoading(true); 9 | retrieveData().then((data) => { 10 | setIsLoading(false); 11 | setData(data); 12 | }); 13 | }, [retrieveData]); 14 | 15 | return { data, isLoading }; 16 | } -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/10-react-query/102-react-usequery/public/favicon.ico -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/10-react-query/102-react-usequery/public/logo192.png -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/10-react-query/102-react-usequery/public/logo512.png -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/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 | -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | console.log("Retrieve products"); 9 | return new Promise((resolve) => { 10 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 11 | }); 12 | } 13 | 14 | export { retrieveProducts }; 15 | -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import { ProductsContext } from "../../productsContext"; 3 | 4 | import ProductList from "../components/ProductList"; 5 | 6 | describe("Product list should", () => { 7 | test("show available products", () => { 8 | const products = [ 9 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 10 | ]; 11 | const addToCart = jest.fn(); 12 | 13 | render( 14 | 15 | 16 | 17 | ); 18 | 19 | expect(screen.getByText(/ipad/i)).toBeDefined(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/src/products/useProdutcs.js: -------------------------------------------------------------------------------- 1 | import { useQuery } from "react-query"; 2 | import { retrieveProducts } from "./repositories/ProductsRepository"; 3 | 4 | export const useProducts = () => { 5 | const { data } = useQuery("products", retrieveProducts, { 6 | placeholderData: [], 7 | }); 8 | 9 | return { 10 | products: data 11 | } 12 | } -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/src/productsContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | 3 | const useProductsContext = () => { 4 | const products = useContext(ProductsContext); 5 | return products; 6 | } 7 | 8 | const ProductsContext = createContext(); 9 | 10 | export { ProductsContext, useProductsContext }; -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/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 | -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/src/shoppingcart/reducer.js: -------------------------------------------------------------------------------- 1 | const ADD_TO_CART = "ADD_TO_CART"; 2 | const CHECKOUT = "CHECKOUT"; 3 | 4 | export const reducer = (state, action) => { 5 | switch (action.type) { 6 | case ADD_TO_CART: 7 | return { 8 | ...state, 9 | [action.product.id]: state[action.product.id] 10 | ? ++state[action.product.id] 11 | : 1, 12 | }; 13 | 14 | case CHECKOUT: 15 | return []; 16 | 17 | default: 18 | return state; 19 | } 20 | } 21 | 22 | export const actions = (dispatch) => ({ 23 | addToCart: (product) => dispatch({ type: ADD_TO_CART, product }), 24 | checkout: (products) => dispatch({ type: CHECKOUT, products }), 25 | }); -------------------------------------------------------------------------------- /10-react-query/102-react-usequery/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/10-react-query/103-react-usequery-advanced/public/favicon.ico -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/10-react-query/103-react-usequery-advanced/public/logo192.png -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/10-react-query/103-react-usequery-advanced/public/logo512.png -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/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 | -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import { ProductsContext } from "../../productsContext"; 3 | 4 | import ProductList from "../components/ProductList"; 5 | 6 | describe("Product list should", () => { 7 | test("show available products", () => { 8 | const products = [ 9 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 10 | ]; 11 | const addToCart = jest.fn(); 12 | 13 | render( 14 | 15 | 16 | 17 | ); 18 | 19 | expect(screen.getByText(/ipad/i)).toBeDefined(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/src/products/useProdutcs.js: -------------------------------------------------------------------------------- 1 | import { useQuery } from "react-query"; 2 | import { retrieveProducts } from "./repositories/ProductsRepository"; 3 | 4 | export const useProducts = () => { 5 | const { data } = useQuery("products", retrieveProducts, { 6 | placeholderData: [], 7 | staleTime: 5000 8 | }); 9 | 10 | return { 11 | products: data 12 | } 13 | } -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/src/productsContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | 3 | const useProductsContext = () => { 4 | const products = useContext(ProductsContext); 5 | return products; 6 | } 7 | 8 | const ProductsContext = createContext(); 9 | 10 | export { ProductsContext, useProductsContext }; -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/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 | -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /10-react-query/103-react-usequery-advanced/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts(products) { 2 | return new Promise((resolve, reject) => { 3 | setTimeout(() => { 4 | reject("Purchase error"); 5 | }, 200); 6 | }); 7 | } 8 | 9 | export { buyProducts }; 10 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/111-recoil/public/favicon.ico -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/111-recoil/public/logo192.png -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/111-recoil/public/logo512.png -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/src/products/components/ProductList.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Product = ({ product, addToCart }) => { 4 | return ( 5 |
6 |
7 | {product.title} - {product.price} € 8 | {product.inventory ? ` x ${product.inventory}` : null} 9 |
10 | 11 | 12 |
13 | ); 14 | }; 15 | 16 | const ProductList = ({ products, addToCart }) => { 17 | return ( 18 |
19 |

Products

20 | {products.map((product) => ( 21 | 22 | ))} 23 |
24 | ); 25 | }; 26 | 27 | export default ProductList; 28 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | import { useRecoilValue } from "recoil"; 4 | 5 | import { productsValuesState } from "./state/atoms"; 6 | 7 | const ProductListWrapper = ({ addToCart }) => { 8 | const products = useRecoilValue(productsValuesState); 9 | return ; 10 | }; 11 | 12 | export default ProductListWrapper; 13 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/src/products/state/atoms.js: -------------------------------------------------------------------------------- 1 | import { selector } from "recoil"; 2 | 3 | import { retrieveProducts } from "../repositories/ProductsRepository"; 4 | 5 | export const productsState = selector({ 6 | key: "products", 7 | get: async () => { 8 | const products = await retrieveProducts(); 9 | 10 | return products.reduce((result, product) => { 11 | result[product.id] = product; 12 | return result; 13 | }, {}); 14 | }, 15 | }); 16 | 17 | export const productsValuesState = selector({ 18 | key: "productsValues", 19 | get: async ({ get }) => { 20 | const products = get(productsState); 21 | 22 | return Object.values(products); 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { useRecoilValue } from "recoil"; 2 | 3 | import ShoppingCart from "./components/ShoppingCart"; 4 | 5 | import { 6 | shoppingCartProductsState, 7 | shoppingCartTotalState, 8 | } from "./state/atoms"; 9 | 10 | const ShoppingCartWrapper = ({ checkout }) => { 11 | const products = useRecoilValue(shoppingCartProductsState); 12 | const total = useRecoilValue(shoppingCartTotalState); 13 | 14 | return ; 15 | }; 16 | 17 | export default ShoppingCartWrapper; 18 | -------------------------------------------------------------------------------- /11-state-management-alternatives/111-recoil/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/112-xstate/public/favicon.ico -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/112-xstate/public/logo192.png -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/112-xstate/public/logo512.png -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import { ProductsContext } from "../../productsContext"; 3 | 4 | import ProductList from "../components/ProductList"; 5 | 6 | describe("Product list should", () => { 7 | test("show available products", () => { 8 | const products = [ 9 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 10 | ]; 11 | const addToCart = jest.fn(); 12 | 13 | render( 14 | 15 | 16 | 17 | ); 18 | 19 | expect(screen.getByText(/ipad/i)).toBeDefined(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/src/products/useProdutcs.js: -------------------------------------------------------------------------------- 1 | import { useQuery } from "react-query"; 2 | import { retrieveProducts } from "./repositories/ProductsRepository"; 3 | 4 | export const useProducts = () => { 5 | const { data } = useQuery("products", retrieveProducts, { 6 | placeholderData: [], 7 | staleTime: 5000 8 | }); 9 | 10 | return { 11 | products: data 12 | } 13 | } -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/src/productsContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | 3 | const useProductsContext = () => { 4 | const products = useContext(ProductsContext); 5 | return products; 6 | } 7 | 8 | const ProductsContext = createContext(); 9 | 10 | export { ProductsContext, useProductsContext }; -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts(products) { 2 | return new Promise((resolve, reject) => { 3 | setTimeout(() => { 4 | reject("Purchase error"); 5 | }, 200); 6 | }); 7 | } 8 | 9 | export { buyProducts }; 10 | -------------------------------------------------------------------------------- /11-state-management-alternatives/112-xstate/src/useToggle.js: -------------------------------------------------------------------------------- 1 | import { createMachine } from "xstate"; 2 | import { useMachine } from "@xstate/react"; 3 | 4 | const toggleMachine = createMachine({ 5 | id: "toggle", 6 | initial: "active", 7 | states: { 8 | inactive: { 9 | on: { TOGGLE: "active" } 10 | }, 11 | active: { 12 | on: { TOGGLE: "inactive" } 13 | } 14 | } 15 | }); 16 | 17 | export const useToggle = () => { 18 | const [current, send] = useMachine(toggleMachine); 19 | const active = current.matches("active"); 20 | 21 | const toggle = () => send("TOGGLE"); 22 | 23 | return { 24 | active, 25 | toggle 26 | } 27 | } -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/113-jotai/public/favicon.ico -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/113-jotai/public/logo192.png -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/113-jotai/public/logo512.png -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/src/products/components/ProductList.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Product = ({ product, addToCart }) => { 4 | return ( 5 |
6 |
7 | {product.title} - {product.price} € 8 | {product.inventory ? ` x ${product.inventory}` : null} 9 |
10 | 11 | 12 |
13 | ); 14 | }; 15 | 16 | const ProductList = ({ products, addToCart }) => { 17 | return ( 18 |
19 |

Products

20 | {products.map((product) => ( 21 | 22 | ))} 23 |
24 | ); 25 | }; 26 | 27 | export default ProductList; 28 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | import { useAtom } from "jotai"; 4 | 5 | import { productsValuesState } from "./state/atoms"; 6 | 7 | const ProductListWrapper = ({ addToCart }) => { 8 | const [products] = useAtom(productsValuesState); 9 | 10 | return ; 11 | }; 12 | 13 | export default ProductListWrapper; 14 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/src/products/state/atoms.js: -------------------------------------------------------------------------------- 1 | import { atom } from "jotai"; 2 | 3 | import { retrieveProducts } from "../repositories/ProductsRepository"; 4 | 5 | export const productsState = atom(async () => { 6 | const products = await retrieveProducts(); 7 | 8 | return products.reduce((result, product) => { 9 | result[product.id] = product; 10 | return result; 11 | }, {}); 12 | }); 13 | 14 | export const productsValuesState = atom((get) => { 15 | const products = get(productsState); 16 | 17 | return Object.values(products); 18 | }); 19 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { useAtom } from "jotai"; 2 | 3 | import ShoppingCart from "./components/ShoppingCart"; 4 | 5 | import { 6 | shoppingCartProductsState, 7 | shoppingCartTotalState, 8 | } from "./state/atoms"; 9 | 10 | const ShoppingCartWrapper = ({ checkout }) => { 11 | const [products] = useAtom(shoppingCartProductsState); 12 | const [total] = useAtom(shoppingCartTotalState); 13 | 14 | return ; 15 | }; 16 | 17 | export default ShoppingCartWrapper; 18 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-jotai/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/README.md: -------------------------------------------------------------------------------- 1 | # valtio 2 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/113-valtio/public/favicon.ico -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/113-valtio/public/logo192.png -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/113-valtio/public/logo512.png -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Suspense } from "react"; 2 | import { render } from "react-dom"; 3 | 4 | import Products from "./products"; 5 | import ShoppingCart from "./shoppingcart"; 6 | 7 | import { state } from "./shoppingcart/state"; 8 | 9 | const App = () => { 10 | return ( 11 | <> 12 | 13 | 14 | 15 | ); 16 | }; 17 | 18 | render( 19 | Loading...}> 20 | 21 | , 22 | document.getElementById("root") 23 | ); 24 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/src/products/components/ProductList.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Product = ({ product, addToCart }) => { 4 | return ( 5 |
6 |
7 | {product.title} - {product.price} € 8 | {product.inventory ? ` x ${product.inventory}` : null} 9 |
10 | 11 | 12 |
13 | ); 14 | }; 15 | 16 | const ProductList = ({ products, addToCart }) => { 17 | return ( 18 |
19 |

Products

20 | {products.map((product) => ( 21 | 22 | ))} 23 |
24 | ); 25 | }; 26 | 27 | export default ProductList; 28 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | import { useSnapshot } from "valtio"; 4 | 5 | import { state as productState } from "./state"; 6 | import { state as shoppingCartState } from "../shoppingcart/state"; 7 | 8 | const ProductListWrapper = () => { 9 | const snapProduct = useSnapshot(productState); 10 | const snapShoppingCart = useSnapshot(shoppingCartState); 11 | 12 | const products = Object.values(snapProduct.remoteProducts); 13 | 14 | return ( 15 | 16 | ); 17 | }; 18 | 19 | export default ProductListWrapper; 20 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/src/products/state/index.js: -------------------------------------------------------------------------------- 1 | import { proxy } from "valtio"; 2 | 3 | import { retrieveProducts } from "../repositories/ProductsRepository"; 4 | 5 | async function findRecords() { 6 | const products = await retrieveProducts(); 7 | 8 | products.forEach((product) => { 9 | state.products[product.id] = product; 10 | }); 11 | 12 | return state.products; 13 | } 14 | 15 | export const state = proxy({ 16 | products: {}, 17 | remoteProducts: findRecords(), 18 | }); 19 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-valtio/src/shoppingcart/state/index.js: -------------------------------------------------------------------------------- 1 | import { proxy } from "valtio"; 2 | 3 | export const state = proxy({ 4 | shoppingcart: {}, 5 | shoppingcartValues: [], 6 | 7 | addToCart: (product) => { 8 | if (state.shoppingcart[product.id]) { 9 | state.shoppingcart[product.id]++; 10 | } else { 11 | state.shoppingcart[product.id] = 1; 12 | } 13 | 14 | state.shoppingcartValues.push(product); 15 | }, 16 | 17 | checkout: () => { 18 | state.shoppingcart = {}; 19 | state.shoppingcartValues = []; 20 | }, 21 | }); 22 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/113-zustand/public/favicon.ico -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/113-zustand/public/logo192.png -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/11-state-management-alternatives/113-zustand/public/logo512.png -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/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 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /11-state-management-alternatives/113-zustand/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/12-extra/121-redux-toolkit-typescript/public/favicon.ico -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/12-extra/121-redux-toolkit-typescript/public/logo192.png -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/12-extra/121-redux-toolkit-typescript/public/logo512.png -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/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 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/config/store.ts: -------------------------------------------------------------------------------- 1 | import { Action, configureStore, ThunkAction } from "@reduxjs/toolkit"; 2 | import { createLogger } from "redux-logger"; 3 | 4 | import productReducers from "../products/slices"; 5 | import shoppingCartReducers from "../shoppingcart/slices"; 6 | 7 | 8 | const store = configureStore({ 9 | reducer: { 10 | products: productReducers, 11 | shoppingcart: shoppingCartReducers, 12 | }, 13 | middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(createLogger()) 14 | }); 15 | 16 | 17 | export type AppDispatch = typeof store.dispatch; 18 | export type RootState = ReturnType; 19 | export type AppThunk = ThunkAction< 20 | ReturnType, 21 | RootState, 22 | unknown, 23 | Action 24 | >; 25 | 26 | export default store; -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "react-dom"; 2 | import { Provider } from "react-redux"; 3 | import store, { AppDispatch } from "./config/store"; 4 | 5 | import Products from "./products"; 6 | import { listProducts } from "./products/slices"; 7 | import ShoppingCart from "./shoppingcart"; 8 | 9 | (store.dispatch as AppDispatch)(listProducts()); 10 | 11 | render( 12 | 13 | 14 | 15 | , 16 | document.getElementById("root") 17 | ); 18 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/products/index.tsx: -------------------------------------------------------------------------------- 1 | import { useSelector, useDispatch } from "react-redux"; 2 | 3 | import ProductList from "./components/ProductList"; 4 | import { addToCart } from "../shoppingcart/slices"; 5 | import { selectAll } from "./slices"; 6 | import { AppDispatch } from "../config/store"; 7 | 8 | const Component = () => { 9 | const products = useSelector(selectAll); 10 | const dispatch = useDispatch(); 11 | 12 | return ( 13 | { 16 | dispatch(addToCart(data)); 17 | }} 18 | /> 19 | ); 20 | }; 21 | 22 | export default Component; 23 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/products/product.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | id: number; 3 | title: string; 4 | price: number; 5 | } -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/products/repositories/ProductsRepository.ts: -------------------------------------------------------------------------------- 1 | import { Product } from "../product"; 2 | 3 | let PRODUCTS_DATA = [ 4 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 5 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 6 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 7 | ]; 8 | 9 | async function retrieveProducts(): Promise { 10 | return new Promise((resolve) => { 11 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 12 | }); 13 | } 14 | 15 | export { retrieveProducts }; 16 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/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 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/shoppingcart/cartProduct.ts: -------------------------------------------------------------------------------- 1 | export interface CartProduct { 2 | id: number; 3 | title: string; 4 | price: number; 5 | quantity: number; 6 | } -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/shoppingcart/index.tsx: -------------------------------------------------------------------------------- 1 | import { useDispatch, useSelector } from "react-redux"; 2 | import { AppDispatch } from "../config/store"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | import { checkout, selectAll } from "./slices"; 7 | 8 | const Component = () => { 9 | const products = useSelector(selectAll); 10 | const dispatch = useDispatch(); 11 | 12 | return dispatch(checkout(products))} />; 13 | }; 14 | 15 | export default Component; 16 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/src/shoppingcart/repositories/CartRepository.ts: -------------------------------------------------------------------------------- 1 | import { CartProduct } from "../cartProduct"; 2 | 3 | async function buyProducts(products: CartProduct[]): Promise { 4 | return new Promise((resolve) => { 5 | setTimeout(() => resolve(), 100); 6 | }); 7 | } 8 | 9 | export { buyProducts }; 10 | -------------------------------------------------------------------------------- /12-extra/121-redux-toolkit-typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/2-unidirectional-data-flow/22-when-to-use-redux/public/favicon.ico -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/2-unidirectional-data-flow/22-when-to-use-redux/public/logo192.png -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/2-unidirectional-data-flow/22-when-to-use-redux/public/logo512.png -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/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-unidirectional-data-flow/22-when-to-use-redux/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, combineReducers, applyMiddleware } from "redux"; 2 | 3 | import thunk from "redux-thunk"; 4 | 5 | import productReducers from "../products/reducers"; 6 | import shoppingCartReducers from "../shoppingcart/reducers"; 7 | 8 | const middlewares = [thunk]; 9 | 10 | const store = createStore( 11 | combineReducers({ 12 | products: productReducers, 13 | shoppingcart: shoppingCartReducers, 14 | }), 15 | applyMiddleware(...middlewares) 16 | ); 17 | 18 | export default store; 19 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/products/actions/index.js: -------------------------------------------------------------------------------- 1 | import { retrieveProducts } from '../repositories/ProductsRepository'; 2 | import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../constants' 3 | 4 | export const listProducts = () => async (dispatch) => { 5 | const products = await retrieveProducts(); 6 | 7 | dispatch({ 8 | type: RECEIVE_PRODUCTS, 9 | products, 10 | }); 11 | }; 12 | 13 | 14 | export const addToCart = (product)=> { 15 | return { 16 | type: ADD_TO_CART, 17 | product, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/products/constants/index.js: -------------------------------------------------------------------------------- 1 | export const RECEIVE_PRODUCTS = "RECEIVE_PRODUCTS"; 2 | export const ADD_TO_CART = "ADD_TO_CART"; -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/products/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { addToCart } from "./actions"; 3 | import ProductList from "./components/ProductList"; 4 | 5 | 6 | const mapStateToProps = (state) => { 7 | const products = Object.values(state.products); 8 | 9 | return { 10 | products, 11 | }; 12 | }; 13 | 14 | export default connect(mapStateToProps, { onAddToCartClicked: addToCart })( 15 | ProductList 16 | ); 17 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/products/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { RECEIVE_PRODUCTS } from "../constants"; 2 | 3 | const initialState = []; 4 | 5 | const reducer = (state = initialState, action) => { 6 | switch (action.type) { 7 | case RECEIVE_PRODUCTS: 8 | return action.products.reduce((result, product) => { 9 | result[product.id] = product; 10 | return result; 11 | }, {}); 12 | default: 13 | return state; 14 | } 15 | }; 16 | 17 | export default reducer; 18 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/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-unidirectional-data-flow/22-when-to-use-redux/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { cart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | cart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/shoppingcart/constants/index.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART = "ADD_TO_CART"; 2 | export const CHECKOUT_REQUEST = "CHECKOUT_REQUEST"; 3 | export const CHECKOUT_SUCCESS = "CHECKOUT_SUCCESS"; 4 | 5 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { checkout } from "./actions"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | const mapStateToProps = (state) => { 7 | const products = state.products; 8 | const productsOnCard = Object.entries(state.shoppingcart.products); 9 | 10 | return { 11 | products: productsOnCard.map(([key, value]) => { 12 | const product = products[key]; 13 | product.quantity = value; 14 | 15 | return product; 16 | }), 17 | }; 18 | }; 19 | 20 | export default connect(mapStateToProps, { onCheckoutClicked: checkout })( 21 | ShoppingCart 22 | ); 23 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/shoppingcart/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { ADD_TO_CART, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | const initialState = { 4 | products: {}, 5 | }; 6 | 7 | const reducer = (state = initialState, action) => { 8 | switch (action.type) { 9 | case ADD_TO_CART: 10 | const productId = action.product.id; 11 | let quantity = 0; 12 | 13 | if (state.products[productId]) { 14 | quantity = state.products[productId]; 15 | } 16 | 17 | quantity++; 18 | 19 | return { 20 | ...state, 21 | products: { ...state.products, [action.product.id]: quantity }, 22 | }; 23 | 24 | case CHECKOUT_SUCCESS: 25 | return { products: {} } 26 | default: 27 | return state; 28 | } 29 | }; 30 | 31 | export default reducer; 32 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/22-when-to-use-redux/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/23-checking-functional-patterns-by-test/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | targets: { 7 | node: "current", 8 | }, 9 | }, 10 | ], 11 | "@babel/preset-react", 12 | ], 13 | }; 14 | -------------------------------------------------------------------------------- /2-unidirectional-data-flow/23-checking-functional-patterns-by-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "23-checking-functional-patterns-by-test", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "jest" 7 | }, 8 | "dependencies": { 9 | "immer": "^9.0.6", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-redux": "^7.2.2", 13 | "redux": "^4.0.5" 14 | }, 15 | "devDependencies": { 16 | "@babel/core": "^7.13.10", 17 | "@babel/preset-env": "^7.13.10", 18 | "@babel/preset-react": "^7.12.13", 19 | "@testing-library/react": "^11.2.5", 20 | "babel-jest": "^26.6.3", 21 | "jest": "^26.6.3", 22 | "react-test-renderer": "^17.0.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /3-redux-first-steps/31-redux-store-by-test/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | targets: { 7 | node: "current", 8 | }, 9 | }, 10 | ], 11 | "@babel/preset-react", 12 | ], 13 | }; 14 | -------------------------------------------------------------------------------- /3-redux-first-steps/31-redux-store-by-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "31-redux-store-by-test", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "jest" 7 | }, 8 | "dependencies": { 9 | "immer": "^9.0.6", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-redux": "^7.2.2", 13 | "redux": "^4.0.5" 14 | }, 15 | "devDependencies": { 16 | "@babel/core": "^7.13.10", 17 | "@babel/preset-env": "^7.13.10", 18 | "@babel/preset-react": "^7.12.13", 19 | "@testing-library/react": "^11.2.5", 20 | "babel-jest": "^26.6.3", 21 | "jest": "^26.6.3", 22 | "react-test-renderer": "^17.0.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/32-redux-shopping-cart/public/favicon.ico -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/32-redux-shopping-cart/public/logo192.png -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/32-redux-shopping-cart/public/logo512.png -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/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 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, combineReducers } from "redux"; 2 | 3 | import productReducers from "../products/reducers"; 4 | import shoppingCartReducers from "../shoppingcart/reducers"; 5 | 6 | const store = createStore( 7 | combineReducers({ 8 | products: productReducers, 9 | shoppingcart: shoppingCartReducers, 10 | }), 11 | ); 12 | 13 | export default store; 14 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/actions"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/products/actions/index.js: -------------------------------------------------------------------------------- 1 | import { retrieveProducts } from '../repositories/ProductsRepository'; 2 | import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../constants' 3 | 4 | export const listProducts = () => { 5 | const products = retrieveProducts(); 6 | 7 | return { 8 | type: RECEIVE_PRODUCTS, 9 | products, 10 | }; 11 | }; 12 | 13 | 14 | export const addToCart = (product)=> { 15 | return { 16 | type: ADD_TO_CART, 17 | product, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/products/constants/index.js: -------------------------------------------------------------------------------- 1 | export const RECEIVE_PRODUCTS = "RECEIVE_PRODUCTS"; 2 | export const ADD_TO_CART = "ADD_TO_CART"; -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/products/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { addToCart } from "./actions"; 3 | import ProductList from "./components/ProductList"; 4 | 5 | 6 | const mapStateToProps = (state) => { 7 | const products = Object.values(state.products); 8 | 9 | return { 10 | products, 11 | }; 12 | }; 13 | 14 | export default connect(mapStateToProps, { onAddToCartClicked: addToCart })( 15 | ProductList 16 | ); 17 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/products/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { RECEIVE_PRODUCTS } from "../constants"; 2 | 3 | const initialState = []; 4 | 5 | const reducer = (state = initialState, action) => { 6 | switch (action.type) { 7 | case RECEIVE_PRODUCTS: 8 | return action.products.reduce((result, product) => { 9 | result[product.id] = product; 10 | return result; 11 | }, {}); 12 | default: 13 | return state; 14 | } 15 | }; 16 | 17 | export default reducer; 18 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | // async function retrieveProducts() { 8 | // return new Promise((resolve) => { 9 | // setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | // }); 11 | // } 12 | 13 | function retrieveProducts() { 14 | return PRODUCTS_DATA; 15 | } 16 | 17 | export { retrieveProducts }; 18 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/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 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/32-redux-shopping-cart/src/shoppingcart/actions/index.js -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/shoppingcart/constants/index.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART = "ADD_TO_CART"; 2 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | 3 | import ShoppingCart from "./components/ShoppingCart"; 4 | 5 | const mapStateToProps = (state) => { 6 | const products = state.products; 7 | const productsOnCard = Object.entries(state.shoppingcart.products); 8 | 9 | return { 10 | products: productsOnCard.map(([key, value]) => { 11 | const product = products[key]; 12 | product.quantity = value; 13 | 14 | return product; 15 | }), 16 | }; 17 | }; 18 | 19 | export default connect(mapStateToProps)( 20 | ShoppingCart 21 | ); 22 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/shoppingcart/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { ADD_TO_CART } from "../constants"; 2 | 3 | const initialState = { 4 | products: {}, 5 | }; 6 | 7 | const reducer = (state = initialState, action) => { 8 | switch (action.type) { 9 | case ADD_TO_CART: 10 | const productId = action.product.id; 11 | let quantity = 0; 12 | 13 | if (state.products[productId]) { 14 | quantity = state.products[productId]; 15 | } 16 | 17 | quantity++; 18 | 19 | return { 20 | ...state, 21 | products: { ...state.products, [action.product.id]: quantity }, 22 | }; 23 | default: 24 | return state; 25 | } 26 | }; 27 | 28 | export default reducer; 29 | -------------------------------------------------------------------------------- /3-redux-first-steps/32-redux-shopping-cart/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/33-redux-shopping-cart-with-thunk/public/favicon.ico -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/33-redux-shopping-cart-with-thunk/public/logo192.png -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/33-redux-shopping-cart-with-thunk/public/logo512.png -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/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 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, combineReducers, applyMiddleware } from "redux"; 2 | 3 | import thunk from "redux-thunk"; 4 | 5 | import productReducers from "../products/reducers"; 6 | import shoppingCartReducers from "../shoppingcart/reducers"; 7 | 8 | const middlewares = [thunk]; 9 | 10 | const store = createStore( 11 | combineReducers({ 12 | products: productReducers, 13 | shoppingcart: shoppingCartReducers, 14 | }), 15 | applyMiddleware(...middlewares) 16 | ); 17 | 18 | export default store; 19 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/actions"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/products/actions/index.js: -------------------------------------------------------------------------------- 1 | import { retrieveProducts } from '../repositories/ProductsRepository'; 2 | import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../constants' 3 | 4 | export const listProducts = () => async (dispatch) => { 5 | const products = await retrieveProducts(); 6 | 7 | dispatch({ 8 | type: RECEIVE_PRODUCTS, 9 | products, 10 | }); 11 | }; 12 | 13 | 14 | export const addToCart = (product)=> { 15 | return { 16 | type: ADD_TO_CART, 17 | product, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/products/constants/index.js: -------------------------------------------------------------------------------- 1 | export const RECEIVE_PRODUCTS = "RECEIVE_PRODUCTS"; 2 | export const ADD_TO_CART = "ADD_TO_CART"; -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/products/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { addToCart } from "./actions"; 3 | import ProductList from "./components/ProductList"; 4 | 5 | 6 | const mapStateToProps = (state) => { 7 | const products = Object.values(state.products); 8 | 9 | return { 10 | products, 11 | }; 12 | }; 13 | 14 | export default connect(mapStateToProps, { onAddToCartClicked: addToCart })( 15 | ProductList 16 | ); 17 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/products/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { RECEIVE_PRODUCTS } from "../constants"; 2 | 3 | const initialState = []; 4 | 5 | const reducer = (state = initialState, action) => { 6 | switch (action.type) { 7 | case RECEIVE_PRODUCTS: 8 | return action.products.reduce((result, product) => { 9 | result[product.id] = product; 10 | return result; 11 | }, {}); 12 | default: 13 | return state; 14 | } 15 | }; 16 | 17 | export default reducer; 18 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/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 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { cart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | cart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/shoppingcart/constants/index.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART = "ADD_TO_CART"; 2 | export const CHECKOUT_REQUEST = "CHECKOUT_REQUEST"; 3 | export const CHECKOUT_SUCCESS = "CHECKOUT_SUCCESS"; 4 | 5 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { checkout } from "./actions"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | const mapStateToProps = (state) => { 7 | const products = state.products; 8 | const productsOnCard = Object.entries(state.shoppingcart.products); 9 | 10 | return { 11 | products: productsOnCard.map(([key, value]) => { 12 | const product = products[key]; 13 | product.quantity = value; 14 | 15 | return product; 16 | }), 17 | }; 18 | }; 19 | 20 | export default connect(mapStateToProps, { onCheckoutClicked: checkout })( 21 | ShoppingCart 22 | ); 23 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/shoppingcart/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { ADD_TO_CART, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | const initialState = { 4 | products: {}, 5 | }; 6 | 7 | const reducer = (state = initialState, action) => { 8 | switch (action.type) { 9 | case ADD_TO_CART: 10 | const productId = action.product.id; 11 | let quantity = 0; 12 | 13 | if (state.products[productId]) { 14 | quantity = state.products[productId]; 15 | } 16 | 17 | quantity++; 18 | 19 | return { 20 | ...state, 21 | products: { ...state.products, [action.product.id]: quantity }, 22 | }; 23 | 24 | case CHECKOUT_SUCCESS: 25 | return { products: {} } 26 | default: 27 | return state; 28 | } 29 | }; 30 | 31 | export default reducer; 32 | -------------------------------------------------------------------------------- /3-redux-first-steps/33-redux-shopping-cart-with-thunk/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/34-redux-dev-tools/public/favicon.ico -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/34-redux-dev-tools/public/logo192.png -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/3-redux-first-steps/34-redux-dev-tools/public/logo512.png -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/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 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, combineReducers, applyMiddleware } from "redux"; 2 | import { composeWithDevTools } from "redux-devtools-extension"; 3 | 4 | import { createLogger } from "redux-logger"; 5 | import thunk from "redux-thunk"; 6 | 7 | import productReducers from "../products/reducers"; 8 | import shoppingCartReducers from "../shoppingcart/reducers"; 9 | 10 | const middlewares = [thunk]; 11 | if (process.env.NODE_ENV !== "production") { 12 | middlewares.push(createLogger()); 13 | } 14 | 15 | const store = createStore( 16 | combineReducers({ 17 | products: productReducers, 18 | shoppingcart: shoppingCartReducers, 19 | }), 20 | composeWithDevTools(applyMiddleware(...middlewares)) 21 | ); 22 | 23 | export default store; 24 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/actions"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/products/actions/index.js: -------------------------------------------------------------------------------- 1 | import { retrieveProducts } from '../repositories/ProductsRepository'; 2 | import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../constants' 3 | 4 | export const listProducts = () => async (dispatch) => { 5 | const products = await retrieveProducts(); 6 | 7 | dispatch({ 8 | type: RECEIVE_PRODUCTS, 9 | products, 10 | }); 11 | }; 12 | 13 | 14 | export const addToCart = (product)=> { 15 | return { 16 | type: ADD_TO_CART, 17 | product, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/products/constants/index.js: -------------------------------------------------------------------------------- 1 | export const RECEIVE_PRODUCTS = "RECEIVE_PRODUCTS"; 2 | export const ADD_TO_CART = "ADD_TO_CART"; -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/products/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { addToCart } from "./actions"; 3 | import ProductList from "./components/ProductList"; 4 | 5 | 6 | const mapStateToProps = (state) => { 7 | const products = Object.values(state.products); 8 | 9 | return { 10 | products, 11 | }; 12 | }; 13 | 14 | export default connect(mapStateToProps, { onAddToCartClicked: addToCart })( 15 | ProductList 16 | ); 17 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/products/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { RECEIVE_PRODUCTS } from "../constants"; 2 | 3 | const initialState = []; 4 | 5 | const reducer = (state = initialState, action) => { 6 | switch (action.type) { 7 | case RECEIVE_PRODUCTS: 8 | return action.products.reduce((result, product) => { 9 | result[product.id] = product; 10 | return result; 11 | }, {}); 12 | default: 13 | return state; 14 | } 15 | }; 16 | 17 | export default reducer; 18 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/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 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { cart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | cart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/shoppingcart/constants/index.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART = "ADD_TO_CART"; 2 | export const CHECKOUT_REQUEST = "CHECKOUT_REQUEST"; 3 | export const CHECKOUT_SUCCESS = "CHECKOUT_SUCCESS"; 4 | 5 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { checkout } from "./actions"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | const mapStateToProps = (state) => { 7 | const products = state.products; 8 | const productsOnCard = Object.entries(state.shoppingcart.products); 9 | 10 | return { 11 | products: productsOnCard.map(([key, value]) => { 12 | const product = products[key]; 13 | product.quantity = value; 14 | 15 | return product; 16 | }), 17 | }; 18 | }; 19 | 20 | export default connect(mapStateToProps, { onCheckoutClicked: checkout })( 21 | ShoppingCart 22 | ); 23 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/shoppingcart/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { ADD_TO_CART, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | const initialState = { 4 | products: {}, 5 | }; 6 | 7 | const reducer = (state = initialState, action) => { 8 | switch (action.type) { 9 | case ADD_TO_CART: 10 | const productId = action.product.id; 11 | let quantity = 0; 12 | 13 | if (state.products[productId]) { 14 | quantity = state.products[productId]; 15 | } 16 | 17 | quantity++; 18 | 19 | return { 20 | ...state, 21 | products: { ...state.products, [action.product.id]: quantity }, 22 | }; 23 | 24 | case CHECKOUT_SUCCESS: 25 | return { products: {} } 26 | default: 27 | return state; 28 | } 29 | }; 30 | 31 | export default reducer; 32 | -------------------------------------------------------------------------------- /3-redux-first-steps/34-redux-dev-tools/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/4-redux-problems-and-solutions/42-redux-immer/public/favicon.ico -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/4-redux-problems-and-solutions/42-redux-immer/public/logo192.png -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/4-redux-problems-and-solutions/42-redux-immer/public/logo512.png -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/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 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, combineReducers, applyMiddleware } from "redux"; 2 | import { composeWithDevTools } from "redux-devtools-extension"; 3 | 4 | import { createLogger } from "redux-logger"; 5 | import thunk from "redux-thunk"; 6 | 7 | import productReducers from "../products/reducers"; 8 | import shoppingCartReducers from "../shoppingcart/reducers"; 9 | 10 | const middlewares = [thunk]; 11 | if (process.env.NODE_ENV !== "production") { 12 | middlewares.push(createLogger()); 13 | } 14 | 15 | const store = createStore( 16 | combineReducers({ 17 | products: productReducers, 18 | shoppingcart: shoppingCartReducers, 19 | }), 20 | composeWithDevTools(applyMiddleware(...middlewares)) 21 | ); 22 | 23 | export default store; 24 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/actions"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/products/actions/index.js: -------------------------------------------------------------------------------- 1 | import { retrieveProducts } from '../repositories/ProductsRepository'; 2 | import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../constants' 3 | 4 | export const listProducts = () => async (dispatch) => { 5 | const products = await retrieveProducts(); 6 | 7 | dispatch({ 8 | type: RECEIVE_PRODUCTS, 9 | products, 10 | }); 11 | }; 12 | 13 | 14 | export const addToCart = (product)=> { 15 | return { 16 | type: ADD_TO_CART, 17 | product, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/products/constants/index.js: -------------------------------------------------------------------------------- 1 | export const RECEIVE_PRODUCTS = "RECEIVE_PRODUCTS"; 2 | export const ADD_TO_CART = "ADD_TO_CART"; -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/products/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { addToCart } from "./actions"; 3 | import ProductList from "./components/ProductList"; 4 | 5 | 6 | const mapStateToProps = (state) => { 7 | const products = Object.values(state.products); 8 | 9 | return { 10 | products, 11 | }; 12 | }; 13 | 14 | export default connect(mapStateToProps, { onAddToCartClicked: addToCart })( 15 | ProductList 16 | ); 17 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/products/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { RECEIVE_PRODUCTS } from "../constants"; 2 | import produce from "immer"; 3 | 4 | const initialState = []; 5 | 6 | const reducer = produce((draft = initialState, action) => { 7 | const { type } = action; 8 | 9 | if (type === RECEIVE_PRODUCTS) { 10 | draft = action.products.reduce((result, product) => { 11 | result[product.id] = product; 12 | return result; 13 | }, {}); 14 | } 15 | 16 | return draft; 17 | }); 18 | 19 | export default reducer; 20 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/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 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { cart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | cart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/shoppingcart/constants/index.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART = "ADD_TO_CART"; 2 | export const CHECKOUT_REQUEST = "CHECKOUT_REQUEST"; 3 | export const CHECKOUT_SUCCESS = "CHECKOUT_SUCCESS"; 4 | 5 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { checkout } from "./actions"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | const mapStateToProps = (state) => { 7 | const products = state.products; 8 | const productsOnCard = Object.entries(state.shoppingcart.products); 9 | 10 | return { 11 | products: productsOnCard.map(([key, value]) => { 12 | return { ...products[key], quantity: value }; 13 | }), 14 | }; 15 | }; 16 | 17 | export default connect(mapStateToProps, { onCheckoutClicked: checkout })( 18 | ShoppingCart 19 | ); 20 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/shoppingcart/reducers/index.js: -------------------------------------------------------------------------------- 1 | import produce from "immer"; 2 | 3 | import { ADD_TO_CART, CHECKOUT_SUCCESS } from "../constants"; 4 | 5 | const initialState = { 6 | products: {}, 7 | }; 8 | 9 | const reducer = produce((draft = initialState, action) => { 10 | const { type, product } = action; 11 | 12 | if (type === ADD_TO_CART) { 13 | draft.products[product.id] = ++draft.products[product.id] || 1; 14 | } else if(type === CHECKOUT_SUCCESS) { 15 | draft.products = {}; 16 | } 17 | 18 | return draft; 19 | }); 20 | 21 | export default reducer; 22 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/42-redux-immer/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/4-redux-problems-and-solutions/43-redux-performance-improvements/public/favicon.ico -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/4-redux-problems-and-solutions/43-redux-performance-improvements/public/logo192.png -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/4-redux-problems-and-solutions/43-redux-performance-improvements/public/logo512.png -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/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 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, combineReducers, applyMiddleware } from "redux"; 2 | import { composeWithDevTools } from "redux-devtools-extension"; 3 | 4 | import { createLogger } from "redux-logger"; 5 | import thunk from "redux-thunk"; 6 | 7 | import productReducers from "../products/reducers"; 8 | import shoppingCartReducers from "../shoppingcart/reducers"; 9 | 10 | const middlewares = [thunk]; 11 | if (process.env.NODE_ENV !== "production") { 12 | middlewares.push(createLogger()); 13 | } 14 | 15 | const store = createStore( 16 | combineReducers({ 17 | products: productReducers, 18 | shoppingcart: shoppingCartReducers, 19 | }), 20 | composeWithDevTools(applyMiddleware(...middlewares)) 21 | ); 22 | 23 | export default store; 24 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/actions"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/products/actions/index.js: -------------------------------------------------------------------------------- 1 | import { retrieveProducts } from '../repositories/ProductsRepository'; 2 | import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../constants' 3 | 4 | export const listProducts = () => async (dispatch) => { 5 | const products = await retrieveProducts(); 6 | 7 | dispatch({ 8 | type: RECEIVE_PRODUCTS, 9 | products, 10 | }); 11 | }; 12 | 13 | 14 | export const addToCart = (product)=> { 15 | return { 16 | type: ADD_TO_CART, 17 | product, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/products/constants/index.js: -------------------------------------------------------------------------------- 1 | export const RECEIVE_PRODUCTS = "RECEIVE_PRODUCTS"; 2 | export const ADD_TO_CART = "ADD_TO_CART"; -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/products/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { addToCart } from "./actions"; 3 | import ProductList from "./components/ProductList"; 4 | 5 | import { createSelector } from "reselect"; 6 | 7 | const selectProducts = (state) => state.products; 8 | const productsResult = (products) => Object.values(products); 9 | 10 | const retrieveProducts = createSelector(selectProducts, productsResult); 11 | 12 | const mapStateToProps = (state) => { 13 | return { 14 | products: retrieveProducts(state), 15 | }; 16 | }; 17 | 18 | export default connect(mapStateToProps, { onAddToCartClicked: addToCart })( 19 | ProductList 20 | ); 21 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/products/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { RECEIVE_PRODUCTS } from "../constants"; 2 | import produce from "immer"; 3 | 4 | const initialState = []; 5 | 6 | const reducer = produce((draft = initialState, action) => { 7 | const { type } = action; 8 | 9 | if (type === RECEIVE_PRODUCTS) { 10 | draft = action.products.reduce((result, product) => { 11 | result[product.id] = product; 12 | return result; 13 | }, {}); 14 | } 15 | 16 | return draft; 17 | }); 18 | 19 | export default reducer; 20 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/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 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { cart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | cart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/shoppingcart/constants/index.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART = "ADD_TO_CART"; 2 | export const CHECKOUT_REQUEST = "CHECKOUT_REQUEST"; 3 | export const CHECKOUT_SUCCESS = "CHECKOUT_SUCCESS"; 4 | 5 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { checkout } from "./actions"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | const mapStateToProps = (state) => { 7 | const products = state.products; 8 | const productsOnCard = Object.entries(state.shoppingcart.products); 9 | 10 | return { 11 | products: productsOnCard.map(([key, value]) => { 12 | return { ...products[key], quantity: value }; 13 | }), 14 | }; 15 | }; 16 | 17 | export default connect(mapStateToProps, { onCheckoutClicked: checkout })( 18 | ShoppingCart 19 | ); 20 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/shoppingcart/reducers/index.js: -------------------------------------------------------------------------------- 1 | import produce from "immer"; 2 | 3 | import { ADD_TO_CART, CHECKOUT_SUCCESS } from "../constants"; 4 | 5 | const initialState = { 6 | products: {}, 7 | }; 8 | 9 | const reducer = produce((draft = initialState, action) => { 10 | const { type, product } = action; 11 | 12 | if (type === ADD_TO_CART) { 13 | draft.products[product.id] = ++draft.products[product.id] || 1; 14 | } else if(type === CHECKOUT_SUCCESS) { 15 | draft.products = {}; 16 | } 17 | 18 | return draft; 19 | }); 20 | 21 | export default reducer; 22 | -------------------------------------------------------------------------------- /4-redux-problems-and-solutions/43-redux-performance-improvements/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/5-redux-toolkit/51-redux-toolkit-config/public/favicon.ico -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/5-redux-toolkit/51-redux-toolkit-config/public/logo192.png -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/5-redux-toolkit/51-redux-toolkit-config/public/logo512.png -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/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 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import { createLogger } from "redux-logger"; 3 | 4 | import productReducers from "../products/reducers"; 5 | import shoppingCartReducers from "../shoppingcart/reducers"; 6 | 7 | 8 | export default configureStore({ 9 | reducer: { 10 | products: productReducers, 11 | shoppingcart: shoppingCartReducers, 12 | }, 13 | middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(createLogger()), 14 | }); 15 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/actions"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/products/actions/index.js: -------------------------------------------------------------------------------- 1 | import { retrieveProducts } from '../repositories/ProductsRepository'; 2 | import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../constants' 3 | 4 | export const listProducts = () => async (dispatch) => { 5 | const products = await retrieveProducts(); 6 | 7 | dispatch({ 8 | type: RECEIVE_PRODUCTS, 9 | products, 10 | }); 11 | }; 12 | 13 | 14 | export const addToCart = (product)=> { 15 | return { 16 | type: ADD_TO_CART, 17 | product, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/products/constants/index.js: -------------------------------------------------------------------------------- 1 | export const RECEIVE_PRODUCTS = "RECEIVE_PRODUCTS"; 2 | export const ADD_TO_CART = "ADD_TO_CART"; -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/products/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { addToCart } from "./actions"; 3 | import ProductList from "./components/ProductList"; 4 | 5 | import { createSelector } from "reselect"; 6 | 7 | const selectProducts = (state) => state.products; 8 | const productsResult = (products) => Object.values(products); 9 | 10 | const retrieveProducts = createSelector(selectProducts, productsResult); 11 | 12 | const mapStateToProps = (state) => { 13 | return { 14 | products: retrieveProducts(state), 15 | }; 16 | }; 17 | 18 | export default connect(mapStateToProps, { onAddToCartClicked: addToCart })( 19 | ProductList 20 | ); 21 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/products/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { RECEIVE_PRODUCTS } from "../constants"; 2 | import produce from "immer"; 3 | 4 | const initialState = []; 5 | 6 | const reducer = produce((draft = initialState, action) => { 7 | const { type } = action; 8 | 9 | if (type === RECEIVE_PRODUCTS) { 10 | draft = action.products.reduce((result, product) => { 11 | result[product.id] = product; 12 | return result; 13 | }, {}); 14 | } 15 | 16 | return draft; 17 | }); 18 | 19 | export default reducer; 20 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/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 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { cart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | cart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/shoppingcart/constants/index.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART = "ADD_TO_CART"; 2 | export const CHECKOUT_REQUEST = "CHECKOUT_REQUEST"; 3 | export const CHECKOUT_SUCCESS = "CHECKOUT_SUCCESS"; 4 | 5 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { checkout } from "./actions"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | const mapStateToProps = (state) => { 7 | const products = state.products; 8 | const productsOnCard = Object.entries(state.shoppingcart.products); 9 | 10 | return { 11 | products: productsOnCard.map(([key, value]) => { 12 | return { ...products[key], quantity: value }; 13 | }), 14 | }; 15 | }; 16 | 17 | export default connect(mapStateToProps, { onCheckoutClicked: checkout })( 18 | ShoppingCart 19 | ); 20 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/shoppingcart/reducers/index.js: -------------------------------------------------------------------------------- 1 | import produce from "immer"; 2 | 3 | import { ADD_TO_CART, CHECKOUT_SUCCESS } from "../constants"; 4 | 5 | const initialState = { 6 | products: {}, 7 | }; 8 | 9 | const reducer = produce((draft = initialState, action) => { 10 | const { type, product } = action; 11 | 12 | if (type === ADD_TO_CART) { 13 | draft.products[product.id] = ++draft.products[product.id] || 1; 14 | } else if(type === CHECKOUT_SUCCESS) { 15 | draft.products = {}; 16 | } 17 | 18 | return draft; 19 | }); 20 | 21 | export default reducer; 22 | -------------------------------------------------------------------------------- /5-redux-toolkit/51-redux-toolkit-config/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/5-redux-toolkit/52-redux-toolkit-slice/public/favicon.ico -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/5-redux-toolkit/52-redux-toolkit-slice/public/logo192.png -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/5-redux-toolkit/52-redux-toolkit-slice/public/logo512.png -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/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 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import { createLogger } from "redux-logger"; 3 | 4 | import productReducers from "../products/slices"; 5 | import shoppingCartReducers from "../shoppingcart/slices"; 6 | 7 | 8 | export default configureStore({ 9 | reducer: { 10 | products: productReducers, 11 | shoppingcart: shoppingCartReducers, 12 | }, 13 | middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(createLogger()), 14 | }); 15 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/slices"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/src/products/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { addToCart } from "../shoppingcart/slices"; 3 | import ProductList from "./components/ProductList"; 4 | 5 | import { createSelector } from "reselect"; 6 | 7 | const selectProducts = (state) => state.products; 8 | const productsResult = (products) => Object.values(products); 9 | 10 | const retrieveProducts = createSelector(selectProducts, productsResult); 11 | 12 | const mapStateToProps = (state) => { 13 | return { 14 | products: retrieveProducts(state), 15 | }; 16 | }; 17 | 18 | export default connect(mapStateToProps, { onAddToCartClicked: addToCart })( 19 | ProductList 20 | ); 21 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/src/products/slices/index.js: -------------------------------------------------------------------------------- 1 | import { retrieveProducts } from "../repositories/ProductsRepository"; 2 | 3 | import { createSlice } from "@reduxjs/toolkit"; 4 | 5 | export const productsSlice = createSlice({ 6 | name: "products", 7 | initialState: {}, 8 | reducers: { 9 | receiveProducts: (state, action) => { 10 | const products = action.payload; 11 | 12 | return products.reduce((result, product) => { 13 | result[product.id] = product; 14 | return result; 15 | }, {}); 16 | }, 17 | }, 18 | }); 19 | 20 | export const { receiveProducts } = productsSlice.actions; 21 | 22 | export const listProducts = () => async (dispatch) => { 23 | const products = await retrieveProducts(); 24 | 25 | dispatch(receiveProducts(products)); 26 | }; 27 | 28 | export default productsSlice.reducer; -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/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 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { shoppingcart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | shoppingcart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import { checkout } from "./slices"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | const mapStateToProps = (state) => { 7 | const products = state.products; 8 | const productsOnCard = Object.entries(state.shoppingcart.products); 9 | 10 | return { 11 | products: productsOnCard.map(([key, value]) => { 12 | return { ...products[key], quantity: value }; 13 | }), 14 | }; 15 | }; 16 | 17 | export default connect(mapStateToProps, { onCheckoutClicked: checkout })( 18 | ShoppingCart 19 | ); 20 | -------------------------------------------------------------------------------- /5-redux-toolkit/52-redux-toolkit-slice/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/5-redux-toolkit/53-redux-toolkit-connect-components/public/favicon.ico -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/5-redux-toolkit/53-redux-toolkit-connect-components/public/logo192.png -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/5-redux-toolkit/53-redux-toolkit-connect-components/public/logo512.png -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/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 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import { createLogger } from "redux-logger"; 3 | 4 | import productReducers from "../products/slices"; 5 | import shoppingCartReducers from "../shoppingcart/slices"; 6 | 7 | 8 | export default configureStore({ 9 | reducer: { 10 | products: productReducers, 11 | shoppingcart: shoppingCartReducers, 12 | }, 13 | middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(createLogger()), 14 | }); 15 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/slices"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/src/products/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useSelector, useDispatch } from "react-redux"; 3 | 4 | import ProductList from "./components/ProductList"; 5 | import { addToCart } from "../shoppingcart/slices"; 6 | 7 | const Component = () => { 8 | const products = useSelector((state) => Object.values(state.products)); 9 | const dispatch = useDispatch(); 10 | 11 | return ( 12 | { 15 | dispatch(addToCart(data)); 16 | }} 17 | /> 18 | ); 19 | }; 20 | 21 | export default Component; 22 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/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 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { shoppingcart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | shoppingcart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | import { checkout } from "../shoppingcart/slices"; 7 | 8 | const Component = () => { 9 | const products = useSelector((state) => { 10 | const products = state.products; 11 | const productsOnCard = Object.entries(state.shoppingcart.products); 12 | 13 | return productsOnCard.map(([key, value]) => { 14 | return { ...products[key], quantity: value }; 15 | }); 16 | }); 17 | const dispatch = useDispatch(); 18 | 19 | 20 | return dispatch(checkout())} />; 21 | }; 22 | 23 | export default Component; 24 | -------------------------------------------------------------------------------- /5-redux-toolkit/53-redux-toolkit-connect-components/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/public/favicon.ico -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/public/logo192.png -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/public/logo512.png -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/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 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import { createLogger } from "redux-logger"; 3 | 4 | import productReducers from "../products/slices"; 5 | import shoppingCartReducers from "../shoppingcart/slices"; 6 | 7 | 8 | export default configureStore({ 9 | reducer: { 10 | products: productReducers, 11 | shoppingcart: shoppingCartReducers, 12 | }, 13 | middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(createLogger()), 14 | }); 15 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/slices"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/src/products/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useSelector, useDispatch } from "react-redux"; 3 | 4 | import ProductList from "./components/ProductList"; 5 | import { addToCart } from "../shoppingcart/slices"; 6 | 7 | const Component = () => { 8 | const products = useSelector((state) => Object.values(state.products)); 9 | const dispatch = useDispatch(); 10 | 11 | return ( 12 | { 15 | dispatch(addToCart(data)); 16 | }} 17 | /> 18 | ); 19 | }; 20 | 21 | export default Component; 22 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/src/products/slices/index.js: -------------------------------------------------------------------------------- 1 | import { retrieveProducts } from "../repositories/ProductsRepository"; 2 | 3 | import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; 4 | 5 | export const listProducts = createAsyncThunk( 6 | "products/listProducts", 7 | async () => { 8 | return await retrieveProducts(); 9 | } 10 | ); 11 | 12 | 13 | export const productsSlice = createSlice({ 14 | name: "products", 15 | initialState: {}, 16 | reducers: {}, 17 | extraReducers: { 18 | [listProducts.fulfilled]: (state, action) => { 19 | const products = action.payload; 20 | return products.reduce((result, product) => { 21 | result[product.id] = product; 22 | return result; 23 | }, {}); 24 | }, 25 | }, 26 | }); 27 | 28 | export default productsSlice.reducer; -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/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 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { shoppingcart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | shoppingcart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | import { checkout } from "../shoppingcart/slices"; 7 | 8 | const Component = () => { 9 | const products = useSelector((state) => { 10 | const products = state.products; 11 | const productsOnCard = Object.entries(state.shoppingcart.products); 12 | 13 | return productsOnCard.map(([key, value]) => { 14 | return { ...products[key], quantity: value }; 15 | }); 16 | }); 17 | const dispatch = useDispatch(); 18 | 19 | 20 | return dispatch(checkout())} />; 21 | }; 22 | 23 | export default Component; 24 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/61-redux-toolkit-thunk/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/public/favicon.ico -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/public/logo192.png -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/public/logo512.png -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/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 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/src/config/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import { createLogger } from "redux-logger"; 3 | 4 | import productReducers from "../products/slices"; 5 | import shoppingCartReducers from "../shoppingcart/slices"; 6 | 7 | 8 | export default configureStore({ 9 | reducer: { 10 | products: productReducers, 11 | shoppingcart: shoppingCartReducers, 12 | }, 13 | middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(createLogger()), 14 | }); 15 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import store from "./config/store"; 5 | 6 | import Products from "./products"; 7 | import { listProducts } from "./products/slices"; 8 | import ShoppingCart from "./shoppingcart"; 9 | 10 | store.dispatch(listProducts()); 11 | 12 | render( 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/src/products/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useSelector, useDispatch } from "react-redux"; 3 | 4 | import ProductList from "./components/ProductList"; 5 | import { addToCart } from "../shoppingcart/slices"; 6 | import { selectAll } from "./slices"; 7 | 8 | const Component = () => { 9 | const products = useSelector(selectAll); 10 | const dispatch = useDispatch(); 11 | 12 | return ( 13 | { 16 | dispatch(addToCart(data)); 17 | }} 18 | /> 19 | ); 20 | }; 21 | 22 | export default Component; 23 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/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 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/src/shoppingcart/actions/index.js: -------------------------------------------------------------------------------- 1 | import { CHECKOUT_REQUEST, CHECKOUT_SUCCESS } from "../constants"; 2 | 3 | import { buyProducts } from "../repositories/CartRepository"; 4 | 5 | export const checkout = (products) => async (dispatch, getState) => { 6 | const { shoppingcart } = getState(); 7 | 8 | dispatch({ 9 | type: CHECKOUT_REQUEST, 10 | }); 11 | 12 | await buyProducts(products); 13 | 14 | dispatch({ 15 | type: CHECKOUT_SUCCESS, 16 | shoppingcart, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | 4 | import ShoppingCart from "./components/ShoppingCart"; 5 | 6 | import { checkout, selectAll } from "../shoppingcart/slices"; 7 | 8 | const Component = () => { 9 | const products = useSelector(selectAll); 10 | const dispatch = useDispatch(); 11 | 12 | return dispatch(checkout())} />; 13 | }; 14 | 15 | export default Component; 16 | -------------------------------------------------------------------------------- /6-redux-toolkit-other-patterns/62-redux-toolkit-entity-adapter/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/8-react-hooks/81-react-useState/public/favicon.ico -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/8-react-hooks/81-react-useState/public/logo192.png -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/8-react-hooks/81-react-useState/public/logo512.png -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/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 | -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/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 | -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /8-react-hooks/81-react-useState/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/8-react-hooks/82-react-useReducer/public/favicon.ico -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/8-react-hooks/82-react-useReducer/public/logo192.png -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/8-react-hooks/82-react-useReducer/public/logo512.png -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/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 | -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/src/reducer.js: -------------------------------------------------------------------------------- 1 | const ADD_TO_CART = "ADD_TO_CART"; 2 | const CHECKOUT = "CHECKOUT"; 3 | 4 | export const reducer = (state, action) => { 5 | switch (action.type) { 6 | case ADD_TO_CART: 7 | return { 8 | ...state, 9 | [action.product.id]: state[action.product.id] 10 | ? ++state[action.product.id] 11 | : 1, 12 | }; 13 | 14 | case CHECKOUT: 15 | return []; 16 | 17 | default: 18 | return state; 19 | } 20 | } 21 | 22 | export const actions = (dispatch) => ({ 23 | addToCart: (product) => dispatch({ type: ADD_TO_CART, product }), 24 | checkout: (products) => dispatch({ type: CHECKOUT, products }), 25 | }); -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/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 | -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /8-react-hooks/82-react-useReducer/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/8-react-hooks/83-react-custom-hook/public/favicon.ico -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/8-react-hooks/83-react-custom-hook/public/logo192.png -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/8-react-hooks/83-react-custom-hook/public/logo512.png -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/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 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | 4 | import Products from "./products"; 5 | import ShoppingCart from "./shoppingcart"; 6 | 7 | import { useProducts } from "./products/useProdutcs"; 8 | import { useShoppingCart } from "./shoppingcart/useShoppingCart"; 9 | 10 | const App = () => { 11 | const { products } = useProducts(); 12 | const { addToCart, checkout, productsOnCart } = useShoppingCart(products); 13 | 14 | return ( 15 | <> 16 | 17 | 18 | 19 | ); 20 | }; 21 | 22 | render(, document.getElementById("root")); 23 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import ProductList from "../components/ProductList"; 4 | 5 | describe("Product list should", () => { 6 | test("show available products", () => { 7 | const products = [ 8 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 9 | ]; 10 | 11 | render(); 12 | 13 | expect(screen.getByText(/ipad/i)).toBeDefined(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/src/products/useProdutcs.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { retrieveProducts } from "./repositories/ProductsRepository"; 3 | 4 | export const useProducts = () => { 5 | const [products, setProducts] = useState({}); 6 | 7 | useEffect(() => { 8 | retrieveProducts().then((products) => { 9 | setProducts( 10 | products.reduce((result, product) => { 11 | result[product.id] = product; 12 | return result; 13 | }, {}) 14 | ); 15 | }); 16 | }, []); 17 | 18 | return { 19 | products 20 | } 21 | } -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/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 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/src/shoppingcart/reducer.js: -------------------------------------------------------------------------------- 1 | const ADD_TO_CART = "ADD_TO_CART"; 2 | const CHECKOUT = "CHECKOUT"; 3 | 4 | export const reducer = (state, action) => { 5 | switch (action.type) { 6 | case ADD_TO_CART: 7 | return { 8 | ...state, 9 | [action.product.id]: state[action.product.id] 10 | ? ++state[action.product.id] 11 | : 1, 12 | }; 13 | 14 | case CHECKOUT: 15 | return []; 16 | 17 | default: 18 | return state; 19 | } 20 | } 21 | 22 | export const actions = (dispatch) => ({ 23 | addToCart: (product) => dispatch({ type: ADD_TO_CART, product }), 24 | checkout: (products) => dispatch({ type: CHECKOUT, products }), 25 | }); -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /8-react-hooks/83-react-custom-hook/src/shoppingcart/useShoppingCart.js: -------------------------------------------------------------------------------- 1 | import { useReducer } from "react"; 2 | 3 | import { actions, reducer } from "./reducer"; 4 | 5 | const initialState = {}; 6 | 7 | export const useShoppingCart = (products) => { 8 | const [shoppingcart, dispatch] = useReducer(reducer, initialState); 9 | 10 | function productsOnCart() { 11 | return Object.entries(shoppingcart).map(([key, value]) => { 12 | const product = products[key]; 13 | product.quantity = value; 14 | 15 | return product; 16 | }); 17 | } 18 | 19 | const { addToCart, checkout } = actions(dispatch); 20 | 21 | return { 22 | productsOnCart, 23 | addToCart, 24 | checkout 25 | } 26 | }; -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/9-react-context/91-react-context-foundations/public/favicon.ico -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/9-react-context/91-react-context-foundations/public/logo192.png -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/9-react-context/91-react-context-foundations/public/logo512.png -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/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 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | 4 | import Products from "./products"; 5 | import ShoppingCart from "./shoppingcart"; 6 | 7 | import { useProducts } from "./products/useProdutcs"; 8 | import { useShoppingCart } from "./shoppingcart/useShoppingCart"; 9 | import { ProductsContext } from "./productsContext"; 10 | 11 | const App = () => { 12 | const { products } = useProducts(); 13 | const { addToCart, checkout, productsOnCart } = useShoppingCart(products); 14 | 15 | return ( 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | 23 | render(, document.getElementById("root")); 24 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import { ProductsContext } from "../../productsContext"; 3 | 4 | import ProductList from "../components/ProductList"; 5 | 6 | describe("Product list should", () => { 7 | test("show available products", () => { 8 | const products = [ 9 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 10 | ]; 11 | const addToCart = jest.fn(); 12 | 13 | render( 14 | 15 | 16 | 17 | ); 18 | 19 | expect(screen.getByText(/ipad/i)).toBeDefined(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/products/useProdutcs.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { retrieveProducts } from "./repositories/ProductsRepository"; 3 | 4 | export const useProducts = () => { 5 | const [products, setProducts] = useState({}); 6 | 7 | useEffect(() => { 8 | retrieveProducts().then((products) => { 9 | setProducts( 10 | products.reduce((result, product) => { 11 | result[product.id] = product; 12 | return result; 13 | }, {}) 14 | ); 15 | }); 16 | }, []); 17 | 18 | return { 19 | products 20 | } 21 | } -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/productsContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | const ProductsContext = createContext(); 4 | 5 | export { ProductsContext }; -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/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 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/shoppingcart/reducer.js: -------------------------------------------------------------------------------- 1 | const ADD_TO_CART = "ADD_TO_CART"; 2 | const CHECKOUT = "CHECKOUT"; 3 | 4 | export const reducer = (state, action) => { 5 | switch (action.type) { 6 | case ADD_TO_CART: 7 | return { 8 | ...state, 9 | [action.product.id]: state[action.product.id] 10 | ? ++state[action.product.id] 11 | : 1, 12 | }; 13 | 14 | case CHECKOUT: 15 | return []; 16 | 17 | default: 18 | return state; 19 | } 20 | } 21 | 22 | export const actions = (dispatch) => ({ 23 | addToCart: (product) => dispatch({ type: ADD_TO_CART, product }), 24 | checkout: (products) => dispatch({ type: CHECKOUT, products }), 25 | }); -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /9-react-context/91-react-context-foundations/src/shoppingcart/useShoppingCart.js: -------------------------------------------------------------------------------- 1 | import { useReducer } from "react"; 2 | 3 | import { actions, reducer } from "./reducer"; 4 | 5 | const initialState = {}; 6 | 7 | export const useShoppingCart = (products) => { 8 | const [shoppingcart, dispatch] = useReducer(reducer, initialState); 9 | 10 | function productsOnCart() { 11 | return Object.entries(shoppingcart).map(([key, value]) => { 12 | const product = products[key]; 13 | product.quantity = value; 14 | 15 | return product; 16 | }); 17 | } 18 | 19 | const { addToCart, checkout } = actions(dispatch); 20 | 21 | return { 22 | productsOnCart: productsOnCart(), 23 | addToCart, 24 | checkout 25 | } 26 | }; -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/9-react-context/92-react-useContext/public/favicon.ico -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/9-react-context/92-react-useContext/public/logo192.png -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/9-react-context/92-react-useContext/public/logo512.png -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/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 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | 4 | import Products from "./products"; 5 | import ShoppingCart from "./shoppingcart"; 6 | 7 | import { useProducts } from "./products/useProdutcs"; 8 | import { useShoppingCart } from "./shoppingcart/useShoppingCart"; 9 | import { ProductsContext } from "./productsContext"; 10 | 11 | const App = () => { 12 | const { products } = useProducts(); 13 | const { addToCart, checkout, productsOnCart } = useShoppingCart(products); 14 | 15 | return ( 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | 23 | render(, document.getElementById("root")); 24 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import { ProductsContext } from "../../productsContext"; 3 | 4 | import ProductList from "../components/ProductList"; 5 | 6 | describe("Product list should", () => { 7 | test("show available products", () => { 8 | const products = [ 9 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 10 | ]; 11 | const addToCart = jest.fn(); 12 | 13 | render( 14 | 15 | 16 | 17 | ); 18 | 19 | expect(screen.getByText(/ipad/i)).toBeDefined(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/products/useProdutcs.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { retrieveProducts } from "./repositories/ProductsRepository"; 3 | 4 | export const useProducts = () => { 5 | const [products, setProducts] = useState({}); 6 | 7 | useEffect(() => { 8 | retrieveProducts().then((products) => { 9 | setProducts( 10 | products.reduce((result, product) => { 11 | result[product.id] = product; 12 | return result; 13 | }, {}) 14 | ); 15 | }); 16 | }, []); 17 | 18 | return { 19 | products 20 | } 21 | } -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/productsContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | 3 | const useProductsContext = () => { 4 | const products = useContext(ProductsContext); 5 | return products; 6 | } 7 | 8 | const ProductsContext = createContext(); 9 | 10 | export { ProductsContext, useProductsContext }; -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/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 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/shoppingcart/reducer.js: -------------------------------------------------------------------------------- 1 | const ADD_TO_CART = "ADD_TO_CART"; 2 | const CHECKOUT = "CHECKOUT"; 3 | 4 | export const reducer = (state, action) => { 5 | switch (action.type) { 6 | case ADD_TO_CART: 7 | return { 8 | ...state, 9 | [action.product.id]: state[action.product.id] 10 | ? ++state[action.product.id] 11 | : 1, 12 | }; 13 | 14 | case CHECKOUT: 15 | return []; 16 | 17 | default: 18 | return state; 19 | } 20 | } 21 | 22 | export const actions = (dispatch) => ({ 23 | addToCart: (product) => dispatch({ type: ADD_TO_CART, product }), 24 | checkout: (products) => dispatch({ type: CHECKOUT, products }), 25 | }); -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /9-react-context/92-react-useContext/src/shoppingcart/useShoppingCart.js: -------------------------------------------------------------------------------- 1 | import { useReducer } from "react"; 2 | 3 | import { actions, reducer } from "./reducer"; 4 | 5 | const initialState = {}; 6 | 7 | export const useShoppingCart = (products) => { 8 | const [shoppingcart, dispatch] = useReducer(reducer, initialState); 9 | 10 | function productsOnCart() { 11 | return Object.entries(shoppingcart).map(([key, value]) => { 12 | const product = products[key]; 13 | product.quantity = value; 14 | 15 | return product; 16 | }); 17 | } 18 | 19 | const { addToCart, checkout } = actions(dispatch); 20 | 21 | return { 22 | productsOnCart: productsOnCart(), 23 | addToCart, 24 | checkout 25 | } 26 | }; -------------------------------------------------------------------------------- /9-react-context/93-react-composition/README.md: -------------------------------------------------------------------------------- 1 | # redux-classic 2 | -------------------------------------------------------------------------------- /9-react-context/93-react-composition/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/9-react-context/93-react-composition/public/favicon.ico -------------------------------------------------------------------------------- /9-react-context/93-react-composition/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/9-react-context/93-react-composition/public/logo192.png -------------------------------------------------------------------------------- /9-react-context/93-react-composition/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/react-state-management-course/e85b168c04d65f86310213ce75cde386586fb192/9-react-context/93-react-composition/public/logo512.png -------------------------------------------------------------------------------- /9-react-context/93-react-composition/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 | -------------------------------------------------------------------------------- /9-react-context/93-react-composition/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/UserInfo.js: -------------------------------------------------------------------------------- 1 | export const UserInfo = ({ user }) => ( 2 |
3 | Connected as {user} 4 |
5 | ); -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/products/index.js: -------------------------------------------------------------------------------- 1 | import ProductList from "./components/ProductList"; 2 | 3 | export default ProductList; 4 | -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/products/repositories/ProductsRepository.js: -------------------------------------------------------------------------------- 1 | let PRODUCTS_DATA = [ 2 | { id: 1, title: "iPad 4 Mini", price: 500.01 }, 3 | { id: 2, title: "H&M T-Shirt White", price: 10.99 }, 4 | { id: 3, title: "Charli XCX - Sucker CD", price: 19.99 }, 5 | ]; 6 | 7 | async function retrieveProducts() { 8 | return new Promise((resolve) => { 9 | setTimeout(() => resolve(PRODUCTS_DATA), 100); 10 | }); 11 | } 12 | 13 | export { retrieveProducts }; 14 | -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/products/tests/ProductList.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import { ProductsContext } from "../../productsContext"; 3 | 4 | import ProductList from "../components/ProductList"; 5 | 6 | describe("Product list should", () => { 7 | test("show available products", () => { 8 | const products = [ 9 | { id: 1, title: "iPad", price: 100, quantity: 1, inventory: 100 }, 10 | ]; 11 | const addToCart = jest.fn(); 12 | 13 | render( 14 | 15 | 16 | 17 | ); 18 | 19 | expect(screen.getByText(/ipad/i)).toBeDefined(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/products/useProdutcs.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { retrieveProducts } from "./repositories/ProductsRepository"; 3 | 4 | export const useProducts = () => { 5 | const [products, setProducts] = useState({}); 6 | 7 | useEffect(() => { 8 | retrieveProducts().then((products) => { 9 | setProducts( 10 | products.reduce((result, product) => { 11 | result[product.id] = product; 12 | return result; 13 | }, {}) 14 | ); 15 | }); 16 | }, []); 17 | 18 | return { 19 | products 20 | } 21 | } -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/productsContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | 3 | const useProductsContext = () => { 4 | const products = useContext(ProductsContext); 5 | return products; 6 | } 7 | 8 | const ProductsContext = createContext(); 9 | 10 | export { ProductsContext, useProductsContext }; -------------------------------------------------------------------------------- /9-react-context/93-react-composition/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 | -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/shoppingcart/index.js: -------------------------------------------------------------------------------- 1 | import ShoppingCart from "./components/ShoppingCart"; 2 | 3 | export default ShoppingCart; 4 | -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/shoppingcart/reducer.js: -------------------------------------------------------------------------------- 1 | const ADD_TO_CART = "ADD_TO_CART"; 2 | const CHECKOUT = "CHECKOUT"; 3 | 4 | export const reducer = (state, action) => { 5 | switch (action.type) { 6 | case ADD_TO_CART: 7 | return { 8 | ...state, 9 | [action.product.id]: state[action.product.id] 10 | ? ++state[action.product.id] 11 | : 1, 12 | }; 13 | 14 | case CHECKOUT: 15 | return []; 16 | 17 | default: 18 | return state; 19 | } 20 | } 21 | 22 | export const actions = (dispatch) => ({ 23 | addToCart: (product) => dispatch({ type: ADD_TO_CART, product }), 24 | checkout: (products) => dispatch({ type: CHECKOUT, products }), 25 | }); -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/shoppingcart/repositories/CartRepository.js: -------------------------------------------------------------------------------- 1 | async function buyProducts() { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), 100); 4 | }); 5 | } 6 | 7 | export { buyProducts }; 8 | -------------------------------------------------------------------------------- /9-react-context/93-react-composition/src/shoppingcart/useShoppingCart.js: -------------------------------------------------------------------------------- 1 | import { useReducer } from "react"; 2 | 3 | import { actions, reducer } from "./reducer"; 4 | 5 | const initialState = {}; 6 | 7 | export const useShoppingCart = (products) => { 8 | const [shoppingcart, dispatch] = useReducer(reducer, initialState); 9 | 10 | function productsOnCart() { 11 | return Object.entries(shoppingcart).map(([key, value]) => { 12 | const product = products[key]; 13 | product.quantity = value; 14 | 15 | return product; 16 | }); 17 | } 18 | 19 | const { addToCart, checkout } = actions(dispatch); 20 | 21 | return { 22 | productsOnCart: productsOnCart(), 23 | addToCart, 24 | checkout 25 | } 26 | }; -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # React state management course examples 2 | 3 | [React State Management Course](https://pro.codely.tv/library/gestion-estado-en-react/about) 4 | --------------------------------------------------------------------------------