From cfe9e8b6e714dcdf8dfd52ac37568055f313bdaf Mon Sep 17 00:00:00 2001 From: aybike Date: Thu, 3 Dec 2020 12:38:10 +0100 Subject: [PATCH] STATUS: useContext structured and linked components achieved | Typescript: 1 major error --- src/components/Header.tsx | 21 +++++++++- src/components/Product.tsx | 9 +++- src/components/Products.tsx | 28 ++++++++++--- src/containers/Checkout.tsx | 77 +++++++++++++++++++++++++++-------- src/containers/Home.tsx | 11 +---- src/context/AppContext.tsx | 5 +++ src/hooks/useInitialState.tsx | 45 ++++++++++++++++++++ src/initialState.ts | 14 ++++++- src/routes/App.tsx | 49 ++++++++++++++++------ tsconfig.json | 4 +- 10 files changed, 214 insertions(+), 49 deletions(-) create mode 100644 src/context/AppContext.tsx create mode 100644 src/hooks/useInitialState.tsx diff --git a/src/components/Header.tsx b/src/components/Header.tsx index ee7926a..6c6527c 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,7 +1,25 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { Link } from 'react-router-dom'; +import AppContext from '../context/AppContext'; + +interface ProductsObject { + id: string; + image: string; + title: string; + price: number; + description: string; +} +interface AppState { + cart?: ProductsObject[]; + products?: ProductsObject[]; +} +interface Cart { + state?: AppState; +} const Header = (): JSX.Element => { + const { state = {} } = useContext(AppContext); + const { cart } = state; return ( <> @@ -11,6 +29,7 @@ const Header = (): JSX.Element => { + {cart && cart.length > 0 &&
{cart.length}
} ); diff --git a/src/components/Product.tsx b/src/components/Product.tsx index 519f758..2b6192e 100644 --- a/src/components/Product.tsx +++ b/src/components/Product.tsx @@ -7,8 +7,12 @@ interface ProductsObject { price: number; description: string; } +interface Cart { + productItem: ProductsObject; + handleAddToCart: (productItem: ProductsObject) => void; +} -const Product: React.FunctionComponent<{ productItem: ProductsObject }> = ({ productItem }): JSX.Element => { +const Product: React.FunctionComponent = ({ productItem, handleAddToCart }): JSX.Element => { return ( <> {productItem.title} @@ -17,6 +21,9 @@ const Product: React.FunctionComponent<{ productItem: ProductsObject }> = ({ pro {productItem.price}

{productItem.description}

+ ); }; diff --git a/src/components/Products.tsx b/src/components/Products.tsx index 14cb00e..c4c2d22 100644 --- a/src/components/Products.tsx +++ b/src/components/Products.tsx @@ -1,4 +1,5 @@ -import React from 'react'; +import React, { useContext } from 'react'; +import AppContext from '../context/AppContext'; import Product from './Product'; @@ -9,13 +10,30 @@ interface ProductsObject { price: number; description: string; } +interface AppState { + cart?: ProductsObject[]; + products?: ProductsObject[]; +} +interface Cart { + state?: AppState; + addToCart?: (product: ProductsObject) => ProductsObject[]; +} + +const Products: React.FunctionComponent = () => { + const { state = {}, addToCart } = useContext(AppContext); + const { products } = state; -const Products: React.FunctionComponent<{ productsList: ProductsObject[] }> = ({ productsList }): JSX.Element => { + const handleAddToCart = (product: ProductsObject) => { + if (addToCart) { + addToCart(product); + } + }; return ( <> - {productsList.map((product: ProductsObject) => { - return ; - })} + {products && + products.map((product: ProductsObject) => { + return ; + })} ); }; diff --git a/src/containers/Checkout.tsx b/src/containers/Checkout.tsx index 9ceddd2..8383934 100644 --- a/src/containers/Checkout.tsx +++ b/src/containers/Checkout.tsx @@ -1,27 +1,68 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { Link } from 'react-router-dom'; +import AppContext from '../context/AppContext'; + +interface ProductsObject { + id: string; + image: string; + title: string; + price: number; + description: string; +} +interface AppState { + cart?: ProductsObject[]; + products?: ProductsObject[]; +} +interface Cart { + state?: AppState; + removeFromCart?: (product: ProductsObject, i: number) => ProductsObject[]; +} + +const Checkout: React.FunctionComponent = () => { + const { state = {}, removeFromCart } = useContext(AppContext); + const { cart } = state; + + const handleRemoveFromCart = (product: ProductsObject, i: number) => { + if (removeFromCart) { + removeFromCart(product, i); + alert(JSON.stringify(cart, null, 2)); + } + }; + + const handleSumTotal = () => { + if (cart) { + const reducer = (accumulator: number, currentValue: { price: number }): number => + accumulator + currentValue.price; + const sum = cart.reduce(reducer, 0); + return sum; + } + }; -const Checkout = (): JSX.Element => { return ( <>
- Items list: -
-
-

Item name

- 10$ -
- -
-
-
-

Total price: 10$

- - - + {cart && cart.length > 0 ?

List items

:

No items selected

} + {cart && + cart.map((item, i) => ( +
+
+

{item.title}

+ {item.price} +
+ +
+ ))}
+ {cart && cart.length > 0 && ( +
+

`Total Price: $ ${handleSumTotal()}`

+ + + +
+ )} ); }; diff --git a/src/containers/Home.tsx b/src/containers/Home.tsx index 2123795..bae88aa 100644 --- a/src/containers/Home.tsx +++ b/src/containers/Home.tsx @@ -1,20 +1,11 @@ -import initialState from '../initialState'; import React from 'react'; import Products from '../components/Products'; -interface ProductsObject { - id: string; - image: string; - title: string; - price: number; - description: string; -} -const products: ProductsObject[] = initialState.products; const Home = (): JSX.Element => { return ( <> - + ); }; diff --git a/src/context/AppContext.tsx b/src/context/AppContext.tsx new file mode 100644 index 0000000..bd23728 --- /dev/null +++ b/src/context/AppContext.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +const AppContext = React.createContext({}); + +export default AppContext; diff --git a/src/hooks/useInitialState.tsx b/src/hooks/useInitialState.tsx new file mode 100644 index 0000000..0d187ec --- /dev/null +++ b/src/hooks/useInitialState.tsx @@ -0,0 +1,45 @@ +import { useState } from 'react'; +import initialState from '../initialState'; + +interface StateObject { + id: string; + image: string; + title: string; + price: number; + description: string; +} +interface AppState { + cart?: StateObject[]; + products?: StateObject[]; +} + +interface InitState { + addToCart: (payload: StateObject) => void; + removeFromCart: (payload: StateObject, indexToRemove: number) => void; + state: AppState; +} + +const useInitialState = (): InitState => { + const [state, setState] = useState(initialState); + + const addToCart = (payload: StateObject) => { + setState({ + ...state, + cart: [...state.cart, payload], + }); + }; + const removeFromCart = (_payload: StateObject, indexToRemove: number) => { + setState({ + ...state, + cart: state?.cart?.filter((_item, indexCurrent) => indexCurrent !== indexToRemove), + }); + }; + + return { + addToCart, + removeFromCart, + state, + }; +}; + +export default useInitialState; diff --git a/src/initialState.ts b/src/initialState.ts index df8ea81..94bec5b 100644 --- a/src/initialState.ts +++ b/src/initialState.ts @@ -1,4 +1,16 @@ -const initialState = { +interface ObjectState { + id: string; + image: string; + title: string; + price: number; + description: string; +} +interface State { + cart?: ObjectState[]; + products: ObjectState[]; +} + +const initialState: State = { cart: [], products: [ { diff --git a/src/routes/App.tsx b/src/routes/App.tsx index a49fd70..80d6e31 100644 --- a/src/routes/App.tsx +++ b/src/routes/App.tsx @@ -9,21 +9,46 @@ import Payment from '../containers/Payment'; import Success from '../containers/Success'; import NotFound from '../containers/NotFound'; +import AppContext from '../context/AppContext'; +import useInitialState from '../hooks/useInitialState'; + +// interface StateObject { +// id: string; +// image: string; +// title: string; +// price: number; +// description: string; +// } + +// interface State { +// cart?: StateObject[]; +// products: StateObject[]; +// } + +// interface InitState { +// addToCart: (payload: StateObject) => void; +// removeFromCart: (payload: StateObject) => void; +// state: State; +// } + const App = (): JSX.Element => { + const initialState = useInitialState(); return ( <> - - - - - - - - - - - - + + + + + + + + + + + + + + ); }; diff --git a/tsconfig.json b/tsconfig.json index 4745f94..b9bcbc9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,9 @@ "module": "commonjs", "baseUrl": "src", "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], + "downlevelIteration": true, + "importHelpers": true, + "lib": ["dom", "dom.iterable", "esnext", "es5", "es2015.collection", "es2015.iterable"], "allowJs": true, "allowSyntheticDefaultImports": true, "skipLibCheck": true,