├── .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 |
18 | {data.map(({ id, title }) => (
19 | - {title}
20 | ))}
21 |
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 |
--------------------------------------------------------------------------------