I am working through a tutorial on React and creating an ecommerce store with a Django backend.
I am new to React.
I have been able to get the React "FrontEnd" home page to display the products from the Django "products.py" which is a simple JSON file stored in the Django file system using the React Axios library.
There is a product pop-up which displays the product information when the use clicks on the view button.
I can't work out how to direct the pop-up to the "products.py" file.
It is still drawing its information from the products.js in the React "FrontEnd" file system.
The code is below. Any assistance would be appreciated.
The code for the product page is below.
Bestsellershop.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { handleOutofStock } from '../../../helper/shopHelper';
import { RatingShop } from '../../../helper/helper';
import Quickview from '../../layouts/Quickview';
import { Modal } from 'react-bootstrap';
import axios from 'axios'
class Bestsellershop extends Component {
constructor(props) {
super(props);
this.state = {
error:null,
modalshow: false,
lastActiveBox: -1,
data:[]
}
this.modalShow = this.modalShow.bind(this);
this.modalClose = this.modalClose.bind(this);
}
componentDidMount(){
var str = "GeeksforGeeks";
this.setState({loading:true});
axios
.get('/api/products/')
.then(res=>{
console.log(res.data);
this.setState({data:res.data, loading:false});
})
.catch(err =>{
console.log(str)
this.setState({error:err, loading:false});
});
}
// Modal
modalShow(index) {
this.setState({ modalshow: true, lastActiveBox: index });
}
modalClose() {
this.setState({ modalshow: false });
}
render() {
const{data,error,loading}=this.state;
return (
<div className="section section-padding">
<div className="container">
<div className="section-title centered">
<span className="subtitle">SuperPharmacy Compounding</span>
<h3 className="title mb-0">Our Products</h3>
</div>
<div className="row">
{error && (
<
error
header="There was some error"
content={JSON.stringify(error)}
/>
)}
{/* Data */}
{data.map((item, i) => (
<div className="col-lg-3 col-md-6" key={i}>
<div className="sigma_product style-6">
<div className="sigma_product-thumb">
<Link to={"/product-single/" + item.id}>
<img src={process.env.PUBLIC_URL + "/" + item.image[0]} alt={item.title} />
</Link>
</div>
<div className="sigma_product-body">
<h5 className="sigma_product-title"> <Link to={"/product-single/" + item.id}>{item.title}</Link>
</h5>
<div className="sigma_rating">
{RatingShop(item.rating)}
</div>
<div className="sigma_product-price">
<span>${new Intl.NumberFormat().format((item.price * (100 - item.discount) / 100).toFixed(2))}</span>
{item.discount > 0 || item.discount !== '' ?
<span>${new Intl.NumberFormat().format((item.price).toFixed(2))}</span>
: ''}
</div>
{/* Cart */}
{item.stock === true ?
<Link to="#" className="sigma_btn btn-sm">Add to Cart</Link>
:
<Link to="#" className="sigma_btn btn-sm" onClick={handleOutofStock}> Add to Cart</Link>
}
{/* Quick view */}
<Link to="#" className="sigma_btn btn-sm light" onClick={(e) => this.modalShow(item.id)}> Quick View </Link>
</div>
</div>
</div>
))}
{/* Data */}
{/* Modal (Quick View) */}
<Modal size="lg" show={this.state.modalshow} className="sigma_quick-view-modal" onHide={this.modalClose} aria-labelledby="contained-modal-title-vcenter" centered>
<Modal.Body className="sigma_modal-sec">
<div className="sigma_close" onClick={this.modalClose}>
<span />
<span />
</div>
<Quickview productId={this.state.lastActiveBox} />
</Modal.Body>
</Modal>
</div>
</div>
</div>
);
}
}
export default Bestsellershop;
The code for the modal pop-up is below.
Quickview.js
import React, { Component } from 'react';
import { getProduct, handleOutofStock } from '../../helper/shopHelper';
import { RatingShop, socialShare, getTags } from '../../helper/helper';
import { Link } from 'react-router-dom';
class Quickview extends Component {
constructor(props) {
super(props)
this.state = {
qty: 1
}
this.increment = this.increment.bind(this);
this.decrement = this.decrement.bind(this);
this.openSocialPopup = this.openSocialPopup.bind(this);
}
increment() {
this.setState({
qty: this.state.qty + 1
});
}
decrement() {
this.setState({
qty: this.state.qty > 1 ? this.state.qty - 1 : 1
});
}
handleChange(event) {
this.setState({ qty: event.target.value });
}
// Open window
openSocialPopup(social) {
window.open(social.link, "MsgWindow", "width=600,height=600")
// alert(social.title)
}
render() {
const productId = this.props.productId;
const modalContent = getProduct(productId);
return (
<div className="row sigma_product-single">
<div className="col-md-6">
<div className="sigma_product-single-thumb">
<img src={process.env.PUBLIC_URL + "/" + modalContent.image[0]} alt={modalContent.title} className="w-100" />
</div>
</div>
<div className="col-md-6">
<div className="sigma_product-single-content">
<h3>{modalContent.title}</h3>
<div className="sigma_product-price">
<span>${new Intl.NumberFormat().format((modalContent.price * (100 - modalContent.discount) / 100).toFixed(2))}</span>
{modalContent.discount > 0 || modalContent.discount !== '' ?
<span>${new Intl.NumberFormat().format((modalContent.price).toFixed(2))}</span>
: ''}
</div>
<div className="sigma_rating-wrapper">
<div className="sigma_rating">
{RatingShop(modalContent.rating)}
</div>
<span>{modalContent.reviews.length} Reviews</span>
</div>
<hr />
<p className="sigma_product-excerpt">
{modalContent.shorttext}
</p>
<div className="sigma_product-meta">
<p><strong>Product SKU: <span>#{modalContent.sku}</span></strong></p>
<p><strong>Availablity:
{modalContent.stock === true ?
<span>In Stock</span>
:
<span>Out of Stock</span>
}
</strong></p>
<p><strong>Tags: </strong>
{getTags(modalContent.tags).map((tag, i) => (
<Link to={"/shop/tag/" + tag.id} key={i}>{tag.title} ,</Link>
))}
</p>
</div>
<hr />
<form className="sigma_product-atc-form">
<div className="sigma_product-buttons d-block">
{/* Cart */}
{modalContent.stock === true ?
<button type="button" className="ml-0 btn-block sigma_btn">Add To
Cart <i className="far fa-shopping-basket" /></button>
:
<button type="button" onClick={handleOutofStock} disabled className="ml-0 btn-block sigma_btn">Add To Cart <i className="far fa-shopping-basket" /></button>
}
{/* Wishlist */}
<Link to="#" className="ml-0 btn-block sigma_btn light">Add To Wishlist <i className="far fa-heart" /> </Link>
<Link to="#" className="ml-0 btn-block sigma_btn light">Compare <i className="far fa-compress" />
</Link>
</div>
</form>
{/* Post Meta Start */}
<div className="sigma_post-single-meta">
<div className="sigma_post-single-meta-item sigma_post-share">
<h5>Share</h5>
<ul className="sigma_sm">
{/* Data */}
{socialShare(modalContent.title).map((social, i) => (
<li key={i}>
<Link to="#" onClick={(e) => this.openSocialPopup(social, i)}>
<i className={social.iconClass} />
</Link>
</li>
))}
{/* Data */}
</ul>
</div>
</div>
{/* Post Meta End */}
</div>
</div>
</div>
);
}
}
export default Quickview;
Update - I have located a helper function file called 'ShopHelper.js'. It contains a function getProduct(id). That function refers to an internal json 'shop.json'.
How do I redirect the shopBlock variable to the Django file?! I am very lost
import shopblock from '../data/shop/shop.json';
import category from '../data/shop/category.json';
// Product details
function getProduct(id) {
return shopblock.filter(product => { return product.id === parseInt(id) })[0];
}
// Count Category
Related
I am currently studying fetch and componentDidMount. I tried to get username and comment from this HTTP address http://localhost:3000/data/commentData.json and put them on the feed(kinda Instagram) but the username/comment didn't show up... If you don't mind, could you help me with which part do I miss or something wrong with my code? I really appreciate your help! I will leave a code below!
This is Comment.js what I expect to receive Username and Comment through fetch
import React, { Component } from 'react';
import COMMENT_LIST from './CommentData';
import './Comment.css';
export class Comment extends Component {
constructor() {
super();
this.state = {
commentList: [],
commentValue: '',
};
}
render() {
return (
<>
{/* {this.props.commentAddList.map((comm, idx) => {
return <li key={idx}>{comm}</li>; */}
{/* {COMMENT_LIST.map(comment => {
return (
<li className="commentContainer">
<span className="commentUserName">{comment.userName}</span>
<span className="commentContent">{comment.content}</span>
</li>
);
})} */}
{(this.props.commentList || []).map(comment => {
//props
return (
<li className="commentContainer">
<span className="commentUserName">{comment.userName}</span>
<span className="commentContent">{comment.content}</span>
</li>
);
})}
</>
);
}
}
export default Comment;
This is Feed.js that I tried to add a comment with username and content
import React, { Component } from 'react';
import './Feed.scss';
import {
FaRegHeart,
FaRegComment,
FaRegPaperPlane,
FaRegBookmark,
FaEllipsisH,
} from 'react-icons/fa';
import Comment from '../../../compoonents/Comment/Comment';
import selfiImg from '../../../assets/images/about.png';
import ucscPic from '../../../assets/images/ucscPic.png';
class Feed extends Component {
constructor() {
super();
this.state = {
value: '',
commentList: [],
};
}
componentDidMount() {
fetch('http://localhost:3000/data/commentData.json', {
method: 'GET',
})
.then(res => res.json())
.then(data => {
this.setState({
commentList: data,
});
});
}
getValue = event => {
this.setState({
value: event.target.value,
});
};
addComment = () => {
this.setState({
commentList: this.state.commentList.concat([this.state.value]),
value: '',
});
};
addCommEnter = e => {
if (e.key === 'Enter') {
this.addComment();
}
};
render() {
return (
<div className="feeds">
<div className="article">
<div className="identi">
<img className="selfi-identi" alt="selfi-img" src={selfiImg} />
<span className="name"> Jiwan Jeon </span>
{/* <i id="test" class="fa fa-ellipsis-h" aria-hidden="true"></i> */}
<div className="faEllipsisH">
{/* <FontAwesomeIcon icon={faEllipsisH} /> */}
<FaEllipsisH />
</div>
</div>
<div className="pic">
<img id="feed-pic" src={ucscPic} />
</div>
<div className="show-box">
<div className="reaction-icons">
<FaRegHeart className="heart" />
<FaRegComment className="comment" />
<FaRegPaperPlane className="plane" />
<FaRegBookmark className="bookMark" />
{/* <FontAwesomeIcon icon={faHeart} className="heart" />
<FontAwesomeIcon icon={faComment} className="comment" />
<FontAwesomeIcon icon={faPaperPlane} className="plane" />
<FontAwesomeIcon icon={faBookmark} className="bookMark" /> */}
</div>
<div className="like-counts">
<span>like 4,000</span>
</div>
<div className="check-comments">
<span>
UC Santa Cruz will continue to offer most courses remotely or
online for spring and summer 2021, providing in-person
instruction for a small
</span>
<a id="space" href="">
expanding
</a>
<br />
Check the all comments
<ul className="feed-comments">
<Comment commentAddList={this.state.commentList} />
{/* <li>hello</li> */}
{/* {this.state.commentList.map((comm, idx) => {
return <li key={idx}>{comm}</li>;
})} */}
</ul>
</div>
</div>
<div className="comment">
<i className="fa fa-smile-o" />
<input
// onChange={this.textChange}
// onKeyPress={this.enterClick}
onKeyPress={this.addCommEnter}
onChange={this.getValue}
className="user-input"
type="text"
placeholder="Add Comment..."
value={this.state.value}
/>
<button onClick={this.addComment} className="post">
Post
</button>
</div>
</div>
</div>
);
}
}
export default Feed;
Within your Comment.js file this line is giving you the error: this.props.commentList, because you didn't define such a prop (maybe you misspelled this.props.commentAddList..
I am just a beginner at learning React! (3 weeks). I cloned the Instagram main page for practicing and I tried to make a comment component and apply the Array.map() method to the comment data stored in the parent's state so that as many comment components as the number of comments appear. When I do this without comment component it works well
<ul className="feed-comments">
{/* <Comment commentAddList={this.states.commentList} /> */}
<li>hello</li>
{this.state.commentList.map((comm, idx) => {
return <li key={idx}>{comm}</li>;
})}
</ul>
However, when I create Comment Component and passing parent's state to child's component in Comment.js it doesn' work
and the error message : Cannot read properties of undefined (reading 'commentList')
<ul className="feed-comments">
<Comment commentAddList={this.states.commentList} />
</ul>
This is Comment.js in Component folder
import React, { Component } from 'react';
export class Comment extends Component {
render() {
return (
<>
{/* <li>hello</li> */}
{this.props.commentAddList.map((comm, idx) => {
return <li key={idx}>{comm}</li>;
})}
</>
);
}
}
export default Comment;
I will leave the whole code below just in case!
import React, { Component } from 'react';
// import "../../styles/common.scss";
import './Feed.scss';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import {
faHeart,
faComment,
faPaperPlane,
faBookmark,
faEllipsisH,
} from '#fortawesome/free-solid-svg-icons';
import Comment from '../../../compoonents/Comment/Comment';
class Feed extends Component {
constructor() {
super();
this.state = {
value: '',
commentList: [],
};
}
getValue = event => {
this.setState({
value: event.target.value,
});
};
addComment = () => {
this.setState({
commentList: this.state.commentList.concat([this.state.value]),
value: '',
});
};
addCommEnter = e => {
if (e.key === 'Enter') {
this.addComment();
}
};
// enterClick = e => {
// if (e.key === 'Enter') {
// this.buttonClick;
// e.target.value = '';
// }
// };
render() {
return (
<div className="feeds">
<div className="article">
<div className="identi">
<img className="selfi-identi" alt="selfi-img" src="about.png" />
<span className="name"> Jiwan Jeon </span>
{/* <i id="test" class="fa fa-ellipsis-h" aria-hidden="true"></i> */}
<div className="faEllipsisH">
<FontAwesomeIcon icon={faEllipsisH} />
</div>
</div>
<div className="pic">
<img id="feed-pic" src="ucscPic.png" />
</div>
<div className="show-box">
<div className="reaction-icons">
<FontAwesomeIcon icon={faHeart} className="heart" />
<FontAwesomeIcon icon={faComment} className="comment" />
<FontAwesomeIcon icon={faPaperPlane} className="plane" />
<FontAwesomeIcon icon={faBookmark} className="bookMark" />
</div>
<div className="like-counts">
<span>like 4,000</span>
</div>
<div className="check-comments">
<span>
UC Santa Cruz will continue to offer most courses remotely or
online for spring and summer 2021, providing in-person
instruction for a small
</span>
<a id="space" href="">
expanding
</a>
<br />
Check the all comments
<ul className="feed-comments">
<Comment commentAddList={this.states.commentList} />
{/* <li>hello</li> */}
{/* {this.state.commentList.map((comm, idx) => {
return <li key={idx}>{comm}</li>;
})} */}
</ul>
</div>
</div>
<div className="comment">
<i className="fa fa-smile-o" />
<input
// onChange={this.textChange}
// onKeyPress={this.enterClick}
onKeyPress={this.addCommEnter}
onChange={this.getValue}
className="user-input"
type="text"
placeholder="Add Comment..."
/>
<button onClick={this.addComment} className="post">
Post
</button>
</div>
</div>
</div>
);
}
}
export default Feed;
It would really appreciate your comment!
I only glanced at this question so I don't know if this is the only problem, but:
<ul className="feed-comments">
<Comment commentAddList={this.states.commentList} />
</ul>
needs to be:
<ul className="feed-comments">
<Comment commentAddList={this.state.commentList} />
</ul>
Into DisplayVisit component I have displayed data:
<div>
{(this.state.allVisit.length > 0) ? this.state.allVisit.map(data => {
return (
<div key={data.id} className="card-header mb-2" style={{ background: "#F0F3F7" }}>
<div className="form-group">
<label><b>VisitName:</b> {data.dataContext.VisitName} </label>
</div>
<div className="form-group">
<Link to={`/visit/${data.id}`} className="btn btn-secondary btn-sm" >
<i className="fas fa-arrow-circle-right" /> Details
</Link>
</div>
</div>
)
}) : (
<div className="card-header p-3 mb-2 text-black">
<label><b>Empty</b></label>
</div>
)
}
</div>
When user click Details is moved to next component VisitDetails - this is working.
App.js
<Route exact path="/visit/:id" component={VisitDetails}/>
Then I want have access to id and data.dataContext:
class VisitDetails extends Component {
render() {
const { id } = this.props;
const { data.dataContext } = this.props;
//or const {data} = this.prop
return (
<div>
{id}, {data.dataContext.VisitName}
</div>
)
}
}
but I'm doing something wrong. Im just learning and try to dev first app.
In your DetailVisit component :
<Link to={{ pathname: `/visit/${data.id}`, state: { data: data.dataContext.VisitName} }} className="btn btn-secondary btn-sm">
<i className="fas fa-arrow-circle-right" /> Details
</Link>
In your VisitDetails.js :
class VisitDetails extends Component {
render() {
const { id } = this.props.match.params;
const { data } = this.props.location.state;
return (
<div>
{id}, {data}
</div>
)
}
}
So once I click on the details page I would like to pass the id of the product to the url when you click it. So when i click the details page I would like for it to be myurl/details/itemid i found this StackOverflow answer but i cant seem to get it to work. React Router Pass Param to Component.
I would like for when my details page reloads it reloads withe correct items id.
this is my details page
import React, { Component } from "react";
import { ProductConsumer } from "../context";
import { Link } from "react-router-dom";
import { ButtonContainer } from "./Button";
import DropDown from "./Dropdown";
import ItemCategory from "./ItemCategory";
import { Carousel } from "react-responsive-carousel";
import "react-responsive-carousel/lib/styles/carousel.min.css";
import { AwesomeButton } from "react-awesome-button";
export default class Details extends Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
dropdownOpen: false
};
}
toggle() {
this.setState(prevState => ({
dropdownOpen: !prevState.dropdownOpen
}));
}
render() {
return (
return (
<div className="container-fluid width-100 bg-white py-5 mt-5 ">
{/* ProductInfo */}
<div className="row">
<div className="col mx-auto col-md-6 my-3 ">
<Carousel autoPlay>
<div>
<img src={img} className="img-fluid" alt="product" />
</div>
<div>
<img src={img2} className="img-fluid" alt="product" />
</div>
<div>
<img src={img3} className="img-fluid" alt="product" />
</div>
<div>
<img src={img4} className="img-fluid" alt="product" />
</div>
</Carousel>
{/* Add a Second Image */}
</div>
{/* Product Text */}
<div className="col mx-auto col-md-6 my-3 text-capitalize">
<h1 className="display-3">{title}</h1>
<h4 className="text-black">
<strong className="text-black">
price : <span>$</span>
{price}
</strong>
</h4>
<h4 className="text-blue">
</h4>
<p className="text-black ">{info}</p>
<p className="text-black ">{fabric}</p>
<small className="text-danger">{luxury}</small>
{/* buttons */}
<div>
<Link to="/all">
<AwesomeButton
className="text-capitalize mx-10"
ripple
size="large"
type="primary"
>
Back To Products
</AwesomeButton>
</Link>
<div className="mt-2">
<AwesomeButton
className="text-capitalize m-auto"
ripple
size="medium"
type="primary"
cart
disabled={inCart ? true : false}
onPress={() => {
value.addToCart(id);
}}
>
{inCart ? "inCart" : "add to cart"}
</AwesomeButton>
</div>
<ItemCategory title={category} />
<div className="mt-2">
<img
src="https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/logo-center/9_bdg_secured_by_pp_2line.png"
border="0"
alt="Secured by PayPal"
/>
</div>
</div>
</div>
</div>
</div>
);
}}
</ProductConsumer>
);
}
}
<Route path="/details/:id" component={Details} />
and in the component Details you have access
export default class Details extends Component {
render() {
return(
<div>
<h2>{this.props.match.params.id}</h2>
</div>
)
}
}
I'm making a page where I need to make multiple selections of buttons (like a filter, which I'll use for the next page).
the information from these buttons is coming from an array and I'm using .map () to mount the button list.
My problem is how do I change the state of only the button that was clicked. The way it is now, when I click, all the buttons are active.
How can I solve this?
Thank you.
import React from 'react';
import { Link } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
import { getLevel, getDiscipline } from '../../functions';
import template from './index.pug';
export default class ConfigAssessment extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
constructor(props){
super(props);
this.state = {
level: getLevel(),
discipline: getDiscipline(),
active: '',
first_click: true,
}
}
changeActive = () => {
if (this.state.first_click === true) {
this.setState({
active: 'active',
first_click: false
});
} else {
this.setState({
active: '',
first_click: true,
});
}
}
render() {
return(
<div className="configuration">
<div className="config-title">
<i className="ti-settings" />
<h2>
<FormattedMessage {...messages.configAssessment} />
</h2>
</div>
<div className="config-items">
<div className="form-group">
<label>
<FormattedMessage {...messages.level} />
</label>
<div className="row">
{this.state.level.map((level, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={level.id}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
id={level.id}
onClick={this.changeActive}
>
{level.level}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.discipline} />
</label>
<div className="row">
{ this.state.discipline.map((discipline, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={i}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
{discipline.discipline}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.selectQuestion} />
</label>
<div className="row">
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeAutomatic} />
</button>
</div>
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeManual} />
</button>
</div>
</div>
</div>
<div className="form-group fg-right">
<Link className="btn btn-warning" to="#">
<FormattedMessage {...messages.createAssessment} />
</Link>
</div>
</div>
</div>
);
}
}
Create a separate component for button
class MyButton extends Component {
constructor(props){
super(props);
this.state = {
person: this.props.person
}
}
buttonActiveHandler = () => {
let oldStatus = this.props.person.status;
this.props.person.status = (!oldStatus ? 'active': '');
this.setState({
person:this.props.person
});
}
render() {
return (
<button className={this.state.person.status} onClick={this.buttonActiveHandler}>{this.state.person.name}</button>
);
}
}
export default MyButton;
Then import button component. use map function to for your code block
<div className={classes.Box}>
<h4>Lorem, ipsum.</h4>
{
this.props.survey.map((person, i) => {
return (
<MyButton key={i} person={person}/>
)
})
}
</div>
The easiest solution to this problem is making the component of the content inside the map and then handling the state of that component there. Hence it will maintain individual states.
It depends what you need.
You can create separate component for button with state.
You can also keep state of each button in react state as an array, and then you can get the state of each button by index.
I'd recommend the first solution, it'd easier to manage such state, but it will be harder to get the state of a specific button from the parent component.