Coding a project using React. It's been 3 days I've looking for a solution. I had been learning coding and trying to integrate stripe payment option on my web-app. However, unable to get the proper result. Searched a lot, found no solution.
Code is below :
App.js
import { Elements } from '#stripe/react-stripe-js';
import { loadStripe } from '#stripe/stripe-js';
import { useEffect } from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import './App.css';
import Checkout from './Checkout';
import { auth } from './firebase';
import Header from './Header';
import Home from './Home';
import Login from './Login';
import Payment from './Payment';
import { useStateValue } from './StateProvider';
const promise = loadStripe("pk_test_51KtYdQSJwVy1hdNxUPD5HK8KcKbLDVSic6q6jfdPxuSLYiCjuwzBfE8Eo5u0zVclLgPP33InVTjAyM4rZP3ouWB9009AL3lsZ6");
function App() {
const [{ }, dispatch] = useStateValue();
useEffect(() => {
auth.onAuthStateChanged(authUser => {
console.log("THE USER IS >>>>> ", authUser);
if (authUser) {
dispatch({
type: "SET_USER",
user: authUser
});
}
else {
dispatch({
type: "SET_USER",
user: null
})
}
})
}, []);
return (
<BrowserRouter>
<div className="App">
<Header />
{console.log("load stripe>>>>>>>>",promise)}
<Routes>
<Route path="/payment" element={
<Elements stripe={promise}>
<Payment />
</Elements>
} />
<Route path="/login" element={<Login />} />
<Route path="/checkout" element={<Checkout />} />
<Route path="/" element={<Home />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
Component in which using Stripe and CardElement (Payment.js) :
import { CardElement, useElements, useStripe } from "#stripe/react-stripe-js";
import React, { useState } from "react";
import CurrencyFormat from "react-currency-format";
import { Link } from "react-router-dom";
import CheckoutProduct from "./CheckoutProduct";
import "./Payment.css";
import { getBasketTotal } from "./reducer";
import { useStateValue } from "./StateProvider";
function Payment() {
const [{ basket, user }, dispatch] = useStateValue();
const stripe = useStripe();
const elements = useElements();
const [error,setError]=useState(null);
const [disabled,setDisabled]=useState(true);
const [succeeded,setSucceeded]=useState(false);
const [processing,setProcessing]=useState("");
const handleSubmit = event => {
//do all the stripe stuff
event.preventDefault();
}
const handleChange = event =>{
// Listen for changes in the CardElement
// and display any errors as the customer types card details
setDisabled(event.empty);
setError(event.error ? event.error.message : "");
}
return (
<div className="payment">
<div className="payment__container">
<h1>
Checkout ({<Link to="/checkout">{basket?.length} items</Link>})
</h1>
{/* Payment section - delivery address */}
<div className="payment__section">
<div className="payment__title">
<h3>Delivery Address</h3>
</div>
<div className="payment__address">
<p>{user?.email}</p>
<p>786 Chaurangi Marg</p>
<p>Delhi, India</p>
</div>
</div>
{/* Payment section - Review items */}
<div className="payment__section">
<div className="payment__title">
<h3>Review Items and Delivery</h3>
</div>
<div className="payment__items">
{basket.map(item =>
<CheckoutProduct
id={item.id}
title={item.title}
price={item.price}
rating={item.raing} />
)}
</div>
</div>
{/* Payment section - payment method */}
<div className="payment__section">
<div className="payment__title">
<h3>Payment Method</h3>
</div>
<div className="payment__details">
<form onSubmit={handleSubmit}>
{/*<CardElement />*/}
<div className="card__element">
<CardElement />
</div>
<div className="payment__priceContainer">
<CurrencyFormat
renderText={(value)=>(
<>
<h3>Order Total: {value}</h3>
</>
)}
decimalScale={2}
value={getBasketTotal(basket)}
displayType={"text"}
thousandSeparator={true}
prefix={"₹"}
/>
<button disabled={processing || disabled || succeeded}>
<span>{processing ? <p>Processing</p> : "Buy Now"}</span>
</button>
</div>
{error && <div>{error}</div> }
</form>
</div>
</div>
</div>
</div>
)
}
export default Payment;
Related
I have this little projekt where I enter some user info into a form and on submit it will display it on the same page in a table. This seem to work as intended but then when I click on Home page and then back to the form page the list is empty. I would like the list to persist as long as you browse the site.
I've been struggling with this for a while and would love to get some help.
I'll post the components.
import { useState } from "react";
import { Route, Routes } from "react-router-dom";
import Navbar from "./Components/Navbar";
import Home from "./Components/Home";
import PersonList from "./Components/PersonList";
import PersonDetails from "./Components/PersonDetails";
import LoginForm from "./Components/LoginForm";
import { UserContext } from "./Components/UserContext";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
function App() {
const [value, setValue] = useState(null);
return (
<div className="App">
<UserContext.Provider value={{value, setValue }}>
<Navbar />
<div className="content">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/PersonList" element={<PersonList />} />
<Route path="/Components/PersonDetails/:id/*" element={<PersonDetails />} />
<Route path="/LoginForm" element={<LoginForm />} />
</Routes>
</div>
</UserContext.Provider>
</div>
);
}
export default App;
import { Link } from "react-router-dom";
import { UserContext } from "./UserContext";
import { useContext, useState } from "react";
export default function Navbar() {
const {value, setValue} = useContext(UserContext);
return (
<nav className="navbar">
<h1>React Assignment</h1>
<div className="links">
<Link to="/">Home</Link>
<Link to="/PersonList">Person List</Link>
{ !value && <Link to="/LoginForm">Login</Link> }
{ value && <Link to={"/"} onClick={() => {setValue(null);}} >Logout</Link> }
{value}
</div>
</nav>
)
}
import { useState } from "react";
import UserForm from "./UserForm";
import UserList from "./UserList";
const PersonList = () => {
// create array using useState to store the contact form data.
const [contacts, updateContacts] = useState([]);
// update contact state.
const addContact = (contact) => {
updateContacts([...contacts, contact]);
};
return (
<div className="personlist">
<UserForm addContact={addContact} />
<UserList contacts={contacts} />
</div>
);
}
export default PersonList;
import { useState } from "react";
import { Form, Button } from "react-bootstrap";
// retrieve addContact function from PersonList.js as props.
export default function UserForm({ addContact }) {
// useState hook to manage state in functional components.
const [contactInfo, setContactInfo] = useState({
firstname: "",
lastname: "",
age: "",
nationality: "",
email: "",
});
// update input fields.
const handleChange = (event) => {
setContactInfo({ ...contactInfo, [event.target.name]: event.target.value });
};
// submit data to addContact function.
const handleSubmit = (event) => {
event.preventDefault();
addContact(contactInfo);
// clear input fields after submit
setContactInfo({
firstname: "",
lastname: "",
age: "",
nationality: "",
email: "",
});
};
return (
<div className="form-container w-50">
<Form onSubmit={handleSubmit}>
<h3>Contact Form</h3>
<Form.Control
size="sm"
type="text"
name="firstname"
placeholder="First Name"
required
value={contactInfo.firstname}
onChange={handleChange}
/>
<Form.Control
size="sm"
type="text"
name="lastname"
required
placeholder="Last Name"
value={contactInfo.lastname}
onChange={handleChange}
/>
<Form.Control
size="sm"
type="number"
name="age"
placeholder="Age"
value={contactInfo.age}
onChange={handleChange}
/>
<Form.Control
size="sm"
type="text"
name="nationality"
placeholder="Nationality"
value={contactInfo.nationality}
onChange={handleChange}
/>
<Form.Control
size="sm"
type="email"
name="email"
placeholder="Email"
required
value={contactInfo.email}
onChange={handleChange}
/>
<p></p>
<Button variant="primary" size="sm" type="submit">
Submit Contact
</Button>
<p></p>
</Form>
</div>
);
}
import { Table } from "react-bootstrap";
import uuid from "react-uuid";
import { Link } from "react-router-dom";
// retrieve contacts from PersonList.js as props
export default function UserList({ contacts }) {
if (contacts.length === 0) {
return <h5>The list is empty</h5>;
} else {
return (
<Table className="w-100" bordered hover size="sm">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Nationality</th>
<th>Email</th>
</tr>
</thead>
<tbody className="tablelinks">
{/* use .map to loop */}
{contacts.map((contact) => (
<tr key={uuid()}>
<td>
<Link to={`/Components/PersonDetails/${contact.firstname+contact.lastname}`}>
{contact.firstname}
</Link>
</td>
<td>{contact.lastname}</td>
<td>{contact.age}</td>
<td>{contact.nationality}</td>
<td>{contact.email}</td>
</tr>
))}
</tbody>
</Table>
);
}
}
If you are just needing to persist the contacts state so it is available when navigating to the "/PersonList" path then the obvious solution is to Lift State Up to a common ancestor component that remains mounted while routed components are mounted/unmounted. The App component is this ancestor.
function App() {
const [value, setValue] = useState(null);
// create array using useState to store the contact form data.
const [contacts, updateContacts] = useState([]);
// update contact state.
const addContact = (contact) => {
updateContacts(contacts => [...contacts, contact]);
};
return (
<div className="App">
<UserContext.Provider value={{value, setValue }}>
<Navbar />
<div className="content">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/PersonList" element={<PersonList {...{ addContact, contacts }} />} />
<Route path="/Components/PersonDetails/:id/*" element={<PersonDetails />} />
<Route path="/LoginForm" element={<LoginForm />} />
</Routes>
</div>
</UserContext.Provider>
</div>
);
}
...
const PersonList = ({ contacts, addContact }) => {
return (
<div className="personlist">
<UserForm addContact={addContact} />
<UserList contacts={contacts} />
</div>
);
}
Additionally if you need to also persist the contacts state when the page is reloaded/refreshed then you'll need to persist the state to something more long-term. Initialize/persist the state from/to localStorage.
Example:
function App() {
const [value, setValue] = useState(null);
// create array using useState to store the contact form data.
const [contacts, updateContacts] = useState(
JSON.parse(localStorage.getItem("contacts")) ?? []
);
useEffect(() => {
localStorage.setItem("contacts", JSON.stringify(contacts));
}, [contacts]);
...
}
I'm trying to render a functional component. But for some reason, I'm getting this sentence on the console You need to enable JavaScript to run this app.
This is App.js
import './App.css';
import Home from './components/pages/home/Home';
import SignUp from './components/pages/sign/SignUp';
import Checking from './components/pages/sign/Checking';
import Login from './components/pages/sign/Login';
import Summery from './components/pages/summery/Summery';
import UserList from './components/pages/users/Users';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import UploadFiles from './components/pages/files/UploadFiles';
function App() {
return (
<Router>
<Routes>
<Route exact path='/' element= {<Home />}/>
<Route path='/sign-up' component= {Checking } />
<Route path='/log-in' element= {<Login />} />
<Route path='/admin' element= {<Summery />} />
<Route path='/users' element= {<UserList />} />
<Route path='/files' element= {<UploadFiles />} />
</Routes>
</Router>
);
}
export default App;
Home, Login, Summery, UserList and UploadFiles are React Components and not functions.
Only Checking is a function (Trying to convert everything to a function component).
They all render but only Checking logging into console You need to enable JavaScript to run this app.
This is Checking.js file
import React from "react";
import '../../../App.css';
import Button from '#material-ui/core/Button';
import SendIcon from '#material-ui/icons/Send';
import axios from 'axios';
import bcrypt from 'bcryptjs';
import Navbar from "../../navbar/Navbar";
import { useNavigate } from 'react-router-dom';
export default function Checking() {
const [companyID, setCompanyID] = React.useState('');
const [email, setEmail] = React.useState('');
const navigate = useNavigate();
function handleSubmit(Event) {
Event.preventDefault();
axios.post('/sign-up', {
companyID: companyID,
email: email})
.then(res =>{
//console.log(res.json());
console.log(res);
if(res.status === 200){
//this.app();
//history.push('/login');
}else if (res.status === 400){
console.log("duplicate ID");
}
}).catch(err =>{
// console.log("duplicate ID");
// console.log(err);
});
}
}
return (
<>
<Navbar />
<div className="register-container" ref={this.props.containerRef}>
<h1 className="sign-up">SIGN UP</h1>
<form onSubmit={handleSubmit}>
<div className="form">
<div className="form-group">
{/* <label htmlFor="company id">Company ID : </label> */}
<input
type="number"
name="companyID"
placeholder="Company id"
value={companyID}
onChange={(e) => setCompanyID(e.target.value)}
required/>
</div>
{ <div className="form-group">
{/* <label htmlFor="email">Email : </label> */}
<input
type="text"
name="email" placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required/>
</div> }
<div className="registerbtn">
{/* <button type="submit" class="btn btn-primary">Submit</button> */}
<Button type="submit" endIcon={<SendIcon />} color="primary" variant="contained">
Sign Up
</Button>
</div>
</div>
</form>
</div>
</>
);
}
What am I doing wrong?
Checking is also a react component and you need to render it like the others.
<Route path='/sign-up' element= {<Checking/> } />
I have some user components on which I used the navigation component and I am routing two components on it. when I click on the Device.js component button it should remove device.js and it should redirect to the Keyregister.js component which is having navigation component in it .It should change the value according to the props sent to it. But it is not happening.
user.js
import React from "react";
import { Route, Switch } from "react-router";
import "./User.css";
import Navigation from "./Dashboard/Navigation";
import AuthModel from "./Dashboard/AuthModel";
import DeviceDetails from "./Dashboard/DeviceDetails";
function User() {
return (
<>
<Navigation
link1={""}
link2={"Authmodel"}
link3={"Requests"}
link1name={"Key Status"}
link2name={"Key Upload"}
link3name={"KEY DOWNLOAD"}
/>
<Switch>
<Route path="/User/Dashboard/AuthModel" component={AuthModel} />
<Route path="/User/Dashboard/DeviceDetails" component={DeviceDetails} />
</Switch>
</>
);
}
export default User;
Navigation.js
import React from "react";
import "./Navigation.css";
import { Link } from "react-router-dom";
import { useHistory } from "react-router";
import { Image } from "react-bootstrap";
import EvoVert from "../../../Resources/EvoluteVert.png";
function Navigation(props) {
const history = useHistory();
const handleLogout = (e) => {
e.preventDefault();
localStorage.removeItem("accessToken");
localStorage.removeItem("roleType");
history.push("/");
};
return (
<>
<main classMain="main">
<aside className="sidebar ">
<Image className="Evo-logo" src={EvoVert} />
<nav className="nav">
<ul style={{ textDecoration: "none" }}>
<li>
<Link to={`/User/Dashboard/${props.link2}`}>
{props.link2name}
</Link>
</li>
<li>
<Link to={`/User/Dashboard/${props.link1}`}>
{props.link1name}
</Link>
</li>
<li>
<Link to={`/User/Dashboard/${props.link3}`}>
{props.link3name}
</Link>
</li>
</ul>
</nav>
</aside>
</main>
</>
);
}
export default Navigation;
Device.js
import React, { useState, useEffect } from "react";
import { Form } from "react-bootstrap";
import "./Dashboard.css";
import { useHistory } from "react-router";
import KeyRegister from "./KeyRegister";
function DeviceDetails() {
const history = useHistory();
const [visible, setvisible] = useState(true);
const [serialNum, setSerialNum] = useState("");
const [slot, setSlot] = useState("");
const frmsubmit = (e) => {};
return (
<>
<section className="device-Details_Dashboard">
<div className="container">
<div
className="heading"
style={{
color: "#312450",
fontWeight: "400",
fontSize: "35px",
padding: "1rem",
}}
>
DEVICE DETAILS
</div>
<Form onSubmit={frmsubmit}>
<div>
<div className="device-details-box">
<label>Serial Number</label>
<br />
<input
type="text"
value={serialNum}
onChange={(e) => setSerialNum(e.target.value)}
/>
</div>
<div className="device-details-box">
<label>Slot Number</label>
<br />
<input
type="text"
value={slot}
onChange={(e) => setSlot(e.target.value)}
/>
</div>
</div>
<button className="devDetSub" onClick={frmsubmit}>
<span>SUBMIT</span>
</button>
</Form>
</div>
</section>
{visible && <KeyRegister />}
</>
);
}
export default DeviceDetails;
KeyRegister.js
import React, { useState, useEffect } from "react";
import "./Navigation.css";
import { Route, Switch } from "react-router";
import DUPKT from "./DUPKT";
import MasterSession from "./MasterSession";
import AES from "./AES";
import Navigation from "./Navigation";
function KeyRegister() {
return (
<>
<Navigation
link1={"DUPKT"}
link2={"MasterSession"}
link3={"AES"}
link1name={"DUPKT"}
link2name={"MASTER KEY"}
link3name={"AES"}
/>
<main classMain="main">
<Switch>
<Route path="/User/Dashboard/DUPKT" component={DUPKT} exact />
<Route
path="/User/Dashboard/MasterSession"
component={MasterSession}
exact
/>
<Route path="/User/Dashboard/AES" component={AES} exact />
</Switch>
</main>
</>
);
}
export default KeyRegister;
I cannot see anywhere in your naviagation component props you are passing device details.
<Navigation
link1={""}
link2={"Authmodel"}
link3={"Requests"}
link1name={"Key Status"}
link2name={"Key Upload"}
link3name={"KEY DOWNLOAD"} //should have device details in props
/>
I am trying to follow this SO Answer to "go home" after I close my Modal...
import React, { Suspense, useState } from 'react';
import { BrowserRouter, Route, Switch, useHistory } from "react-router-dom";
import './App.css';
import { Button } from 'reactstrap';
import Slideshow from './components/Slideshow.js';
import LogoHeader from './components/LogoHeader';
import Login from "./components/Login/Login.js";
import ChangePassword from "./components/Login/ChangePassword.js";
import useToken from "./components/useToken";
import NewFooter from "./components/NewFooter";
import GetCategories from "./components/GetCategories";
import { formatter } from './components/common.js'
import { GetCart, Increment, Decrement } from './components/ShoppingCart/CartHandler.js'
import CheckoutModal from './components/ShoppingCart/CheckoutModal.js'
const FeaturedCards = React.lazy(() => import('./components/featuredCards'));
const ProdCard = React.lazy(() => import('./components/productCards'));
const Portal = React.lazy(() => import('./components/Portal/portal'));
function App() {
const { token, setToken } = useToken();
const [cart, setCart] = useState(GetCart());
const [isOpen, setIsOpen] = useState(false);
const history = useHistory();
if (!token) {
return <Login setToken={setToken} />
}
if (token.forcePasswordChange === true) {
return <ChangePassword setToken={setToken} />
}
function handleIncrementClick(item) {
Increment(item.ItemNumber, cart);
setCart(GetCart);
}
function handleDecrementClick(item) {
Decrement(item.ItemNumber, cart);
setCart(GetCart);
}
let onRequestClose = () => {
setIsOpen(false);
setCart(GetCart);
history.push('/')
}
let handleClick = () => {
setIsOpen(true)
}
return (
<div className="App">
<BrowserRouter>
<p className="greeting">Hello, {token.firstName}</p>
<LogoHeader />
<GetCategories />
<Switch>
<Route path="/cart">
<Suspense fallback={<div>Loading...</div>}>
<div>
<table className="table table-striped table-bordered">
<thead>
<tr>
<th className="number">Item Number</th>
<th className="price">Price</th>
<th className="quantity">Quantity</th>
</tr>
</thead>
<tbody>
{cart.map(item =>
<tr key={item.ItemNumber}>
<td>{item.ItemNumber}</td>
<td>{formatter.format(item.Price)}</td>
<td>{item.Quantity}</td>
<td><Button className="BtnIncrement" onClick={() => handleIncrementClick(item)}>{'+'}</Button></td>
<td><Button className="BtnDecrement" onClick={() => handleDecrementClick(item)}>{'-'}</Button></td>
</tr>
)}
</tbody>
</table>
<Button onClick={() => handleClick()}>Checkout</Button>
{isOpen ? <CheckoutModal onRequestClose={onRequestClose} /> : null}
</div>
</Suspense>
</Route>
<Route path="/portal">
<Suspense fallback={<div>Loading...</div>}>
<Portal />
</Suspense>
</Route>
<Route path="/">
<Slideshow id="slideshow" />
<div id="productContainer">
<br />
<h3>Featured Products</h3>
<br />
<Suspense fallback={<div>Loading...</div>}>
<FeaturedCards setCartFunc={setCart} />
</Suspense>
<br />
<h3>Most Popular</h3>
<br />
<Suspense fallback={<div>Loading...</div>}>
<ProdCard />
</Suspense>
<br />
<h3>New Products</h3>
<br />
<Suspense fallback={<div>Loading...</div>}>
<ProdCard />
</Suspense>
</div>
</Route>
</Switch>
<NewFooter />
</BrowserRouter>
</div>
);
}
export default App;
UPDATE
As requested, my CheckoutModal:
import React from 'react';
import "./Checkout.scss"
import AddressBlock from './AddressBlock';
import PaymentBlock from './PaymentBlock';
import ShippingBlock from './ShippingBlock';
import TotalsBlock from './TotalsBlock';
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
class CheckoutModal extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'React',
shippingMethod: null
};
}
setShippingMethod(method) {
this.setState(state => ({ ...state, shippingMethod: method }));
}
render() {
const buttonStyles = {
position: "absolute",
top: "-35px",
right: "10px",
border: "0",
background: "none"
};
return (
<Modal id="checkout"
isOpen
size='xl'>
<button onClick={this.props.onRequestClose} style={buttonStyles}>x</button>
<ModalHeader className="header">
Checkout
</ModalHeader>
<ModalBody>
<div className="row">
<AddressBlock />
<ShippingBlock setShippingMethod={this.setShippingMethod.bind(this)} shippingMethod={this.state.shippingMethod}/>
</div>
<div className="row">
<PaymentBlock onRequestClose={this.props.onRequestClose} />
<TotalsBlock />
</div>
</ModalBody>
</Modal>
);
}
}
export default CheckoutModal;
I am getting history is undefined from my function onRequestClose. I tried prepending this but that didn't work. Is this because App.js is not a class component or rather just a function? Any tips or suggestions would be greatly appreciated.
nodejs 16.13.0
react-router-dom 8.1.2
Issue
You are using/calling the useHistory hook from App but App is the very component rendering the BrowserRouter that provides the routing context to the app, including a valid history object reference.
Solution
Move the BrowserRouter out of App, likely into the index.js where you are rendering App. This is to provide a valid routing context for App and all other components in the App's subtree to access.
Example index.js
...
import { BrowserRouter } from "react-router-dom";
...
const rootElement = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>,
rootElement
);
App
function App() {
const { token, setToken } = useToken();
const [cart, setCart] = useState(GetCart());
const [isOpen, setIsOpen] = useState(false);
const history = useHistory(); // <-- will now be defined
...
const onRequestClose = () => {
setIsOpen(false);
setCart(GetCart);
history.push('/'); // <-- should navigate now
}
...
return (
<div className="App">
<p className="greeting">Hello, {token.firstName}</p>
<LogoHeader />
<GetCategories />
<Switch>
<Route path="/cart">
<Suspense fallback={<div>Loading...</div>}>
<>
<table className="table table-striped table-bordered">
...
</table>
<Button onClick={handleClick}>Checkout</Button>
{isOpen && <CheckoutModal onRequestClose={onRequestClose} />}
</>
</Suspense>
</Route>
...
</Switch>
<NewFooter />
</div>
);
}
Using useRouter in App.js will not work. Becourse its outside the browser router. BrowserRouter wrapped components can only able to use useRouter. Hope this is helpfull.
I am not able to update my comment on the page.
After submiting it is showing comment object in the console log but not on the page Console log image
here is my comment.js
import {COMMENTS} from '../shared/comments';
import * as ActionType from './ActionTypes';
export const Comments=(state=COMMENTS ,action) => {
switch(action.type){
case ActionType.ADD_COMMENT:
var comment = action.payload;
comment.id = state.length;
comment.date = new Date().toISOString();
console.log("Comment: ", comment);
return state.concat(comment);
default:
return state;
};
}
here in my store
import {createStore, combineReducers} from 'redux';
import {Dishes} from './dishes';
import {Comments} from './comments';
import {Leaders} from './leaders';
import {Promotions} from './promotions';
export const ConfigureStore=() =>{
const store=createStore(
combineReducers({
dishes:Dishes,
comments:Comments,
leaders:Leaders,
promotions:Promotions
})
);
return store;
};
here is my action creator
import * as ActionTypes from './ActionTypes';
export const addComment=(dishID,rating,author,comment) => ({
type:ActionTypes.ADD_COMMENT,
payload:{
dishID:dishID,
rating:rating,
author:author,
comment:comment,
}
});
here is my App.js
import React from 'react';
import Main from './components/MainComponent';
import './App.css';
import {BrowserRouter} from 'react-router-dom';
import {Provider} from 'react-redux';
import {ConfigureStore} from './redux/configureStore';
const store=ConfigureStore();
class App extends React.Component {
render()
{
return (
<Provider store={store}>
<BrowserRouter>
<div>
<Main/>
</div>
</BrowserRouter>
</Provider>
);
}
}
export default App;
here is my MainComponent.js
import React from 'react';
import Menu from './MenuComponent';
import DishDetail from './DishdetailComponent';
import Home from './HomeComponent';
import Header from './HeaderComponent';
import Footer from './FooterComponent';
import Contact from './ContactComponent';
import About from './AboutComponent';
import {Switch , Route , Redirect,withRouter } from 'react-router-dom';
import {connect} from 'react-redux';
import {addComment} from '../redux/ActionCreators'
const mapStateToProps=state =>{
return{
dishes:state.dishes,
leaders:state.leaders,
comments:state.comments,
promotions:state.promotions
}
};
const mapDispatchToProps = dispatch => ({
addComment:(dishId,rating,author,comment) => dispatch(addComment(dishId,rating,author,comment))
});
class Main extends React.Component {
render()
{
const HomePage=() => {
return(<Home dish={this.props.dishes.filter((dish) => dish.featured)[0]}
leader={this.props.leaders.filter((leader) => leader.featured)[0]}
promotion={this.props.promotions.filter((promo) => promo.featured)[0]} />);
}
const DishWithId=({match}) => {
return(
<DishDetail dish={this.props.dishes.filter((dish) => dish.id === parseInt(match.params.dishId,10))[0]}
comments={this.props.comments.filter(comment => comment.dishId === parseInt(match.params.dishId,10))}
addComment={this.props.addComment} />
);
};
return (
<div>
<Header/>
<Switch>
<Route path="/home" component={HomePage}/>
<Route exact path="/aboutus" component={() => <About leaders={this.props.leaders}/>}/>
<Route exact path="/menu" component={() => <Menu dishes={this.props.dishes}/>} />
<Route path="/menu/:dishId" component={DishWithId} />
<Route exact path="/contactus" component={() => <Contact/>}/>
<Redirect to="/home"/>
</Switch>
<Footer/>
</div>
);
}
}
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(Main));
here is my dishdetail.js component
import React from 'react';
import '../App.css';
import { Card, CardImg, CardBody, CardTitle, CardText ,Breadcrumb ,BreadcrumbItem ,Button, Modal, ModalHeader, ModalBody, Label,Row} from 'reactstrap';
import { LocalForm, Control,Errors } from 'react-redux-form';
import {Link} from 'react-router-dom';
const maxLength=(len) => (val) => !(val) || (val.length <= len);
const minLength=(len) => (val) => (val) && (val.length >= len);
class CommentForm extends React.Component
{
constructor(props)
{
super(props);
this.state={
isModalOpen:false
};
this.toggleModal=this.toggleModal.bind(this);
this.handelSubmit=this.handelSubmit.bind(this);
}
toggleModal()
{
this.setState({
isModalOpen: !this.state.isModalOpen
});
}
handelSubmit(values)
{
this.props.addComment(this.props.dishId,values.rating,values.author,values.comment);
this.toggleModal();
}
render(){
return(
<React.Fragment>
<Button outline onClick={this.toggleModal}><span className="fa fa-pencil"></span>{' '}Submit Comment</Button>
{/*--Modal For Comment--*/}
<Modal id="commentModal" isOpen={this.state.isModalOpen} toggle={this.toggleModal}>
<ModalHeader toggle={this.toggleModal}>Submit Comment</ModalHeader>
<ModalBody>
<LocalForm onSubmit={(values) => this.handelSubmit(values)} >
<Row className="form-row mt-2">
<Label htmlFor="rating">Rating</Label>
<Control.select model=".rating"
id="rating"
name="rating"
className="form-control"
>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</Control.select>
</Row>
<Row className="form-row mt-2">
<Label htmlFor="author">Your Name</Label>
<Control.text model=".author"
id="author"
name="author"
className="form-control"
placeholder="Your Name"
validators={{
minLength:minLength(3),
maxLength:maxLength(15)
}}
/>
<Errors
className="text-danger"
model=".author"
show="touched"
messages={{
minLength:'Must be greater than 2 characters',
maxLength:'Must be 15 characters or less'
}}/>
</Row>
<Row className="form-row mt-2">
<Label htmlFor="comment">Comment</Label>
<Control.textarea model=".comment"
rows="6"
id="comment"
name="comment"
className="form-control"
/>
</Row>
<Row className="form-row mt-2">
<Button type="submit" color="primary" >Submit</Button>
</Row>
</LocalForm>
</ModalBody>
</Modal>
</React.Fragment>
);
}
}
function RenderDish({dish})
{
return(
<div className="col-12 col-md-5 m-1">
<Card>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardBody>
<CardTitle><strong>{dish.name}</strong></CardTitle>
<CardText>{dish.description}</CardText>
</CardBody>
</Card>
</div>
);
}
function RenderComments({comments,dishId,addComment})
{
if(comments!=null)
{
return(
<div className="col-12 col-md-5 m-1">
<h4>comments</h4>
<ul className="list-unstyled">
{comments.map(comment => {
return(
<li key={comment.id}>
<p>{comment.comment}</p>
<p>--{comment.author} ,{new Intl.DateTimeFormat('en-US',{year:'numeric',month:'short',day:'2-digit'}).format(new Date(Date.parse(comment.date)))}</p>
</li>
);
})}
</ul>
<CommentForm dishId={dishId} addComment={addComment}/>
</div>
);
}
else{
return <div></div>
}
}
function DishDetail(props)
{
if(props.dish!=null)
{
return(
<div className="container">
<div className="row">
<Breadcrumb >
<BreadcrumbItem><Link to="/home">Home</Link></BreadcrumbItem>
<BreadcrumbItem><Link to="/menu">Menu</Link></BreadcrumbItem>
<BreadcrumbItem>{props.dish.name}</BreadcrumbItem>
</Breadcrumb>
<div className="col-12">
<h3>{props.dish.name}</h3>
<hr/>
</div>
</div>
<div className="row">
<RenderDish dish={props.dish}/>
<RenderComments comments={props.comments} dishId={props.dish.id} addComment={props.addComment}/>
</div>
</div>
);
}
else
{
return(
<div></div>
);
}
}
export default DishDetail;
please help !!