Skip to content

Commit

Permalink
STATUS: useContext structured and linked components achieved | Typesc…
Browse files Browse the repository at this point in the history
…ript: 1 major error
  • Loading branch information
crisjumbo committed Dec 3, 2020
1 parent f94f952 commit cfe9e8b
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 49 deletions.
21 changes: 20 additions & 1 deletion 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<Cart>(AppContext);
const { cart } = state;
return (
<>
<span>
Expand All @@ -11,6 +29,7 @@ const Header = (): JSX.Element => {
<Link to="/checkout">
<i className="fas fa-shopping-basket" />
</Link>
{cart && cart.length > 0 && <div>{cart.length}</div>}
</div>
</>
);
Expand Down
9 changes: 8 additions & 1 deletion src/components/Product.tsx
Expand Up @@ -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<Cart> = ({ productItem, handleAddToCart }): JSX.Element => {
return (
<>
<img src={productItem.image} alt={productItem.title} />
Expand All @@ -17,6 +21,9 @@ const Product: React.FunctionComponent<{ productItem: ProductsObject }> = ({ pro
<span>{productItem.price}</span>
<p>{productItem.description}</p>
</div>
<button type="button" onClick={() => handleAddToCart(productItem)}>
Add to cart
</button>
</>
);
};
Expand Down
28 changes: 23 additions & 5 deletions 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';

Expand All @@ -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<Cart>(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 <Product key={product.id} productItem={product} />;
})}
{products &&
products.map((product: ProductsObject) => {
return <Product key={product.id} productItem={product} handleAddToCart={handleAddToCart} />;
})}
</>
);
};
Expand Down
77 changes: 59 additions & 18 deletions 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<Cart>(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 (
<>
<div className="Checkout-content">
Items list:
<div className="Checkout-item">
<div className="Checkout-element">
<h4>Item name</h4>
<span>10$</span>
</div>
<button type="button">
<i className="fas fa-trash-alt" />
</button>
</div>
</div>
<div className="Checkout-sidebar">
<h3>Total price: 10$</h3>
<Link to="/checkout/information">
<button type="button">Continue</button>
</Link>
{cart && cart.length > 0 ? <h3>List items</h3> : <h3>No items selected</h3>}
{cart &&
cart.map((item, i) => (
<div className="Checkout-item" key={i}>
<div className="Checkout-element">
<h4>{item.title}</h4>
<span>{item.price}</span>
</div>
<button type="button" onClick={() => handleRemoveFromCart(item, i)}>
<i className="fas fa-trash-alt" />
</button>
</div>
))}
</div>
{cart && cart.length > 0 && (
<div className="Checkout-sidebar">
<h3>`Total Price: $ ${handleSumTotal()}`</h3>
<Link to="/checkout/information">
<button type="button">Continue</button>
</Link>
</div>
)}
</>
);
};
Expand Down
11 changes: 1 addition & 10 deletions 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 (
<>
<Products productsList={products} />
<Products />
</>
);
};
Expand Down
5 changes: 5 additions & 0 deletions src/context/AppContext.tsx
@@ -0,0 +1,5 @@
import React from 'react';

const AppContext = React.createContext({});

export default AppContext;
45 changes: 45 additions & 0 deletions 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;
14 changes: 13 additions & 1 deletion 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: [
{
Expand Down
49 changes: 37 additions & 12 deletions src/routes/App.tsx
Expand Up @@ -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 (
<>
<Router>
<Layout>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/checkout" component={Checkout} />
<Route exact path="/checkout/information" component={Information} />
<Route exact path="/checkout/payment" component={Payment} />
<Route exact path="/checkout/success" component={Success} />
<Route component={NotFound} />
</Switch>
</Layout>
</Router>
<AppContext.Provider value={initialState}>
<Router>
<Layout>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/checkout" component={Checkout} />
<Route exact path="/checkout/information" component={Information} />
<Route exact path="/checkout/payment" component={Payment} />
<Route exact path="/checkout/success" component={Success} />
<Route component={NotFound} />
</Switch>
</Layout>
</Router>
</AppContext.Provider>
</>
);
};
Expand Down
4 changes: 3 additions & 1 deletion tsconfig.json
Expand Up @@ -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,
Expand Down

0 comments on commit cfe9e8b

Please sign in to comment.