How to create an Order Summary Component - javascript

I'd like to create an order summary component on the right hand side as shown below: How the UI looks
However, I'm not sure how to go about this as I am quite new to MERN stack. This is the component for the how the restaurant details are displayed:
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Grid, CircularProgress } from "#material-ui/core";
import useStyles from "./styles";
import { useParams } from "react-router-dom";
import { restaurantDetails } from "../../actions/restaurants";
import { TextField, Button, Typography, Paper } from "#material-ui/core";
import { LinearProgress } from "#material-ui/core";
import { Container, Row, Col } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.css";
import OrderSummary from "./OrderSummary/OrderSummary";
const RestaurantDetails = (props) => {
const classes = useStyles();
const dispatch = useDispatch();
let { _id } = useParams();
const [restaurantInfo, setRestaurantInfo] = useState();
useEffect(() => {
try {
dispatch(restaurantDetails(_id)).then((res) => setRestaurantInfo(res));
console.log("this is restaurantInfo" + restaurantInfo);
console.log(_id);
} catch (e) {
console.error(e);
}
}, [dispatch]);
return !restaurantInfo ? (
<CircularProgress />
) : (
<Container>
<LinearProgress variant="determinate" value="20" color="secondary" />;
<Row>
<Col sm={8}>
{" "}
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Paper className={classes.paper}>{restaurantInfo.name} </Paper>
</Grid>
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}>{restaurantInfo.categoryname1}</Paper>
</Grid>
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}>{restaurantInfo.categoryname2}</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<div className="">
<img alt="" className="" src="images/3981417.jpg" />
<div className="">
<div className="">
<h3 className="">{restaurantInfo.itemName11}</h3>
<p className="">description here</p>
<h6 className="">£{restaurantInfo.itemPrice11}</h6>
<Button variant="contained" color="secondary">
Add To Order
</Button>
</div>
</div>
</div>
</Grid>
<Grid item xs={6} sm={3}>
<div className="">
<img alt="" className="" src="images/3981417.jpg" />
<div className="">
<div className="">
<h3 className="">{restaurantInfo.itemName12}</h3>
<p className="">description here</p>
<h6 className="">£{restaurantInfo.itemPrice12}</h6>
<Button variant="contained" color="secondary">
Add To Order
</Button>
</div>
</div>
</div>
</Grid>
<Grid item xs={6} sm={3}>
<div className="">
<img alt="" className="" src="images/3981417.jpg" />
<div className="">
<div className="">
<h3 className="">{restaurantInfo.itemName21}</h3>
<p className="">description here</p>
<h6 className="">£{restaurantInfo.itemPrice21}</h6>
<Button variant="contained" color="secondary">
Add To Order
</Button>
</div>
</div>
</div>
</Grid>
<Grid item xs={6} sm={3}>
<div className="">
<img alt="" className="" src="images/3981417.jpg" />
<div className="">
<div className="">
<h3 className="">{restaurantInfo.itemName22}</h3>
<p className="">description here</p>
<h6 className="">£{restaurantInfo.itemPrice22}</h6>
<Button variant="contained" color="secondary">
Add To Order
</Button>
</div>
</div>
</div>
</Grid>
</Grid>
</div>
</Col>
<OrderSummary />
</Row>
</Container>
// <div>
// <h2>Restaurant id is: {_id}</h2>
// <h2>Restaurant name is: {restaurantInfo.name}</h2>
// </div>
);
};
export default RestaurantDetails;
This is the Order Summary component at the moment. Obviously, I would like to display the item names and prices when they are added in order to checkout
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Grid, CircularProgress } from "#material-ui/core";
import useStyles from "./styles";
import { Row, Col } from "react-bootstrap";
import { TextField, Button, Typography, Paper } from "#material-ui/core";
import Card from "#material-ui/core/Card";
import CardContent from "#material-ui/core/CardContent";
import CardHeader from "#material-ui/core/CardHeader";
import CardActions from "#material-ui/core/CardActions";
import { Divider } from "#material-ui/core";
import "bootstrap/dist/css/bootstrap.css";
const OrderTotal = () => {
const classes = useStyles();
return (
<div>
<Col sm={4}>
{" "}
<Card className={classes.root}>
<CardHeader title="Order Summary" className={classes.header} />
<Divider variant="middle" />
<CardContent>
<div className={classes.list}>
<Row>
<Col sm={6}>
<Typography align="center">Display Item</Typography>
</Col>
<Col sm={6}>
<Typography align="center">Display Prices</Typography>
</Col>
</Row>
</div>
</CardContent>
<Divider variant="middle" />
<CardActions className={classes.action}>
<Button variant="contained" color="primary" className={classes.button}>
Order Now
</Button>
</CardActions>
</Card>
</Col>
</div>
);
};
export default OrderTotal;
How do I implement this? How do I pass the prices and names to the order summary component and list them whenever they are added or deleted? I will really appreciate it as I can't seem to figure this out!

You need to store the current cart items in the redux state. You will need an action that adds an item to the cart. Your reducer needs to handle this action and update the cart data. Here is a very basic implementation:
const orderSlice = createSlice({
name: 'order',
initialState: {
items: [],
status: 'unsubmitted'
},
reducers: {
addToOrder: (state, action) => {
state.items.push(action.payload);
},
submitOrder: (state) => {
state.status = 'pending';
}
}
})
export const orderReducer = orderSlice.reducer;
export const {addToOrder, submitOrder} = orderSlice.actions;
Your "Add To Order" Button needs an onClick handler that dispatches your action.
<Button
variant="contained"
color="secondary"
onClick={() => dispatch(addToOrder({
name: restaurantInfo.itemName12,
price: restaurantInfo.itemPrice12
}))}
>
Add To Order
</Button>
Your OrderTotal component would use a useSelector hook to access the cart data from redux.
const orderItems = useSelector(state => state.order.items);
const orderTotal = orderItems.reduce((total, item) => total + item.price, 0);
As a sidenote, you probably should not store restaurantInfo in your component state since it seems like it's already being set in redux. Instead you should access it with a useSelector.

Related

Passing function from child to parent component in react-redux

I have encouneterd a problem that cannot find a solution in react-redux! I have a function that lives on Child component: "onClick={() => addToCart(product)}" Everytime I click on the button on UI of the application an error pops up saying: "TypeError: addToCart is not a function". I have tried several workarounds but in vain:
Parent component code:
class Jeans extends Component {
render () {
return (
<>
<PanelHeader size="sm" />
<ProductList
addToCart = {this.addToCart}
products={jeans}
image={jeans1}
header='Jeans For Men'
description='Foundation Of Contemporary Wardrobes,
Whether Tailored Or Super Skinny, Straight or Slim,
Biker or Destroyed, Our Denim Collection Caters To
Every Style And Silhouette.'
/>
</>
);
}
}
const mapStateToProps = (state)=> {
return {
products: state.products
}
}
const mapDispatchToProps = (dispatch) => {
return {
addToCart: (id) => {dispatch(addToCart(id))}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Jeans);```
and Child component where the function lives:
```class ProductCard extends Component {
render() {
const {image, product, key, addToCart} = this.props
return (
<Col
lg={4}
md={6}
sm={6}
xs={12}
className="font-icon-list"
key={key}
><Card>
<CardImg img src={image} alt="product"/>
<CardBody>
<CardTitle className='d-inline align-middle text-danger'>{product.title}</CardTitle>
<CardTitle className='d-inline align-middle float-right h5'><strong>{product.price}</strong></CardTitle>
<CardText className='my-2'>{product.description}</CardText>
<Button>
<div className="col-md-12 text-center">
<div className="buttons d-flex flex-row">
<div className="cart"><i className="fa fa-shopping-cart"></i>
</div>
<button onClick={() => addToCart(product)} className="btn btn-success cart-button px-5">Add to Cart</button>
</div>
</div>
</Button>
</CardBody>
</Card>
</Col>
)
}
}
export default ProductCard```
**Thank you in advance for your time reviewing my question!**
There is an intermediate component between Parent (Jeans) and Child (Productcard) called (Productlist) so the order goes: "Jeans" --> "ProductList" --> "ProductCard".
ProductList component:
const ProductList = ({products, header, description, image, addToCart}) => {
return (
<div className="content">
<Row>
<Col md={12}>
<Card>
<CardHeader>
<h5 className="title">{header}</h5>
<p className="category">{description}</p>
</CardHeader>
<CardBody className="all-icons">
<Row>
{products.map((product, key) => {
return (
<ProductCard
addToCart = {addToCart}
key={key}
product={product}
image={image}
/>
);
})}
</Row>
</CardBody>
</Card>
</Col>
</Row>
</div>
);
}
export default ProductList;```
index.js consists of the following code:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.css";
import "assets/scss/now-ui-dashboard.scss?v1.5.0";
import "assets/css/demo.css";
import { Provider } from "react-redux";
import AdminLayout from "layouts/Admin.js";
import store from "./redux/store"
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<Switch>
<Route path="/admin" render={(props) => <AdminLayout {...props} />} />
<Redirect to="/admin/dashboard" />
</Switch>
</BrowserRouter>
</Provider>,
document.getElementById("root")
);

react-hook-form field refreshes after submit

I'm sending my react-hook-form field to another function component as a children. After pressing Submit Button, the field refreshes and the value inputed is deleted. What is the problem?
CodeSandBox example is here
My file App.js:
import React from "react";
import "./styles.css";
import { useForm } from "react-hook-form";
import { Box, Button, Grid, TextField } from "#material-ui/core";
export default function App() {
const { register, handleSubmit } = useForm();
function onSubmit(data) {
console.log(data);
}
function FieldComponent(props) {
const { title, children } = props;
return (
<Grid container alignItems="center">
<Grid item xs={3}>
<Box py={5}>
<div fontWeight="bold" fontSize="16">
{title}
</div>
</Box>
</Grid>
<Grid item xs={9}>
<Box py={5}>{children}</Box>
</Grid>
</Grid>
);
}
return (
<div className="App">
<Grid container>
<Grid item xs={12}>
<FieldComponent title="name">
<TextField variant="outlined" name="name" inputRef={register} />
</FieldComponent>
</Grid>
<Grid item xs={12}>
<Button variant="outlined" onClick={handleSubmit(onSubmit)}>
Submit
</Button>
</Grid>
</Grid>
</div>
);
}
It's always a good idea to move your sub-component into its own, otherwise, each re-render will mount and unmount your component.
function FieldComponent(props) {
const { title, children } = props;
return (
<Grid container alignItems="center">
<Grid item xs={3}>
<Box py={5}>
<div fontWeight="bold" fontSize="16">
{title}
</div>
</Box>
</Grid>
<Grid item xs={9}>
<Box py={5}>{children}</Box>
</Grid>
</Grid>
);
}
export default function App() {
const { register, handleSubmit } = useForm();
function onSubmit(data) {
console.log(data);
}
return (
<div className="App">
<Grid container>
<Grid item xs={12}>
<FieldComponent title="name">
<TextField variant="outlined" name="name" inputRef={register} />
</FieldComponent>
</Grid>
<Grid item xs={12}>
<Button variant="outlined" onClick={handleSubmit(onSubmit)}>
Submit
</Button>
</Grid>
</Grid>
</div>
);
}
https://codesandbox.io/s/agitated-darkness-leg7z?file=/src/App.js

No unused Variables

In my useState hook, I am importing context; thus, setUser is going unused and giving me and Eslinting warning. I am unsure of how to stifle this warning and have run out of ideas in order to do so. If anyone has a suggestion or best practices in React for stifling this warning I would greatly appreciate it. the code is as follows:
import React, { useContext } from 'react'
import { Link } from 'react-router-dom'
// Material UI
import Button from '#material-ui/core/Button'
import Grid from '#material-ui/core/Grid'
import Container from '#material-ui/core/Container'
import User from './User'
// context
import { ProfileContext } from '../contexts/ProfileContext'
const Header = ({ isAuth, logout }) => {
const [user, setUser] = useContext(ProfileContext)
return (
<Container maxWidth="lg" style={{ padding: 10 }}>
<Grid container justify="space-between">
<Grid item xs={2}>
<Button color="inherit" component={Link} to="/">
Jobtracker
</Button>
</Grid>
<Grid item xs={10} container justify="flex-end">
<div>
{isAuth ? (
<>
{user && user.user.admin && (
<Button color="inherit" component={Link} to="/admin">
Admin
</Button>
)}
<Button color="inherit" component={Link} to="/profile">
Profile
</Button>
<Button color="inherit" component={Link} to="/dashboard">
Dashboard
</Button>
<Button color="inherit" onClick={logout}>
Logout
</Button>
</>
) : (
<>
<Button color="inherit" component={Link} to="/login">
Login
</Button>
<Button color="inherit" component={Link} to="/signup">
SignUp
</Button>
</>
)}
</div>
</Grid>
</Grid>
</Container>
)
}
export default Header
You don't have to destructure it when you don't need it:
const [user] = useContext(ProfileContext)
In addition, if you just need to setUser, you can skip items while destructuring by using a comma without an variable or constant name:
const [, setUser] = useContext(ProfileContext)
If you are not using setUser just remove it from destructuring

How can i make this const into class on react.js

import React, { useState, Component } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Row, Col, CardHeader, CardBody, Card, } from 'reactstrap';
const ModalBuySell = (props) => {
const {
buttonLabel,
className
} = props;
const datas = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
return (
<div>
<Button color="danger" onClick={toggle}>Buy / Sell</Button>
<Modal isOpen={modal} toggle={toggle} className={className}>
<ModalHeader toggle={toggle}>{datas.name} (No. ID {datas.id}) Transaction(s)</ModalHeader>
<ModalBody>
<Row>
<Col>
<b>In-hand Quantity</b>
</Col>
<Col xs="1">
<i className="fa fa-arrow-right"></i>
</Col>
<Col>
{datas.inHand}
</Col>
</Row>
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={toggle}>Cancel</Button>
</ModalFooter>
</Modal>
</div>
);
}
export default ModalBuySell;
I tried to give my button some onChange function but first i need to make this to class, i'm beginner so i just search on the internet but all the solutions makes me use class instead of my code like that.

React Hooks trying to useState in array ref

I'm trying to work with Hooks in react but i have a doubt about useState and References. My problem is because i want to create multiple references in my jsx but i dont know how use the usestate like a Array, well in the insert of the usestate data.
import React, { useState, useEffect } from "react";
import { Row, Col, Image, ListGroup, Container } from "react-bootstrap";
import AOS from "aos";
import "./css/App.css";
import "aos/dist/aos.css";
import Skills from "./Components/Skills";
import Work from "./Components/Work";
const App = () => {
const [ref, setRef] = useState([]);
useEffect(() => {
AOS.init({
duration: 2000
});
});
function handleOnClick(event) {
ref.scrollIntoView();
}
return (
<div className="App">
<Row>
<Col className="menu text-center" lg={4}>
<div className="picture">
<Image
src={process.env.PUBLIC_URL + "/Images/picture.jpg"}
roundedCircle
/>
</div>
<h1 className="menu-name">Fulanito Detal</h1>
<h4 className="menu-office">Software Engineer - Web Developer</h4>
<div>
<Row>
<Col lg={3}></Col>
<Col lg={6} className="menu-text">
<ListGroup>
<ListGroup.Item
onClick={event => handleOnClick(event)}
active
>
ABOUT
</ListGroup.Item>
<ListGroup.Item>WORK EXPERIENCE</ListGroup.Item>
<ListGroup.Item>EDUCATION</ListGroup.Item>
<ListGroup.Item>SKILLS</ListGroup.Item>
<ListGroup.Item>CONTACT</ListGroup.Item>
</ListGroup>
</Col>
<Col lg={3}></Col>
</Row>
</div>
</Col>
<Col className="info text-center" lg={8}>
<Container>
<div className="about"></div>
<div
className="work"
ref={ref => {
setRef(ref);
}}
>
<Work />
</div>
<div className="education"></div>
<div
className="skills"
ref={ref => {
setRef(ref);
}}
>
<Skills />
</div>
<div className="contact"></div>
</Container>
</Col>
</Row>
</div>
);
};
export default App;
The ref works fine just with one. If clicked about redirect to skills, but i want to use state like array to work with all references but i'm stuck with this one. Thanks for any help!
Here is a simplified example of using the useRef hook:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const App = () => {
const work = React.useRef();
const skills = React.useRef();
return (
<div>
<button onClick={() => work.current.scrollIntoView()}>
WORK EXPERIENCE
</button>
<button onClick={() => skills.current.scrollIntoView()}>SKILLS</button>
<div className="another" />
<div className="work" ref={work}>
WORK SECTION
</div>
<div className="skills" ref={skills}>
SKILL SECTIONS
</div>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Categories