Products Update using Redux When click on " Category" name one Mega Menu, MegaMenu And Product both are different components - javascript

Please See the >>
I want to update Products by clicking on Category Name the MegaMenu, But it does not change. I use redux for state management. Please help me !!
This is MegaMenu Component
import MenuIcon from '#mui/icons-material/Menu';
import './MegaMenu.css';
import { NavLink } from 'react-router-dom';
import ArrowRightIcon from '#mui/icons-material/ArrowRight';
const categories = [
"Sunglass",
"Footwear",
"Men Watch",
"Women Watch",
"Computer",
"SmartPhones",
"Camera",
];
const MegaMenu = () => {
return (
<div className='mega_menu_component'>
<div className='mega_menu_Items'>
<div className='mega_menus'>
<MenuIcon className='mega_menu_icon' style={{ fontSize: '40px', color: '#fff', cursor: 'pointer' }} />
<div class="menu_link_content">
<NavLink className="menu_name" to="/">Home</NavLink>
<NavLink className="menu_name" to="/products">Shop <ArrowRightIcon style={{ fontSize: 'medium' }} />
<ul className="categoryMenu">
{categories.map((categoryName) => (
<li className="categoryMenu-link" > <NavLink style={{ textDecoration: 'none', color: '#000' }} key={categoryName} to={`/products/${categoryName}`}>{categoryName}</NavLink></li>
))}
</ul>
</NavLink>
<NavLink className="menu_name" to="/contact">Contact</NavLink>
<NavLink className="menu_name" to="/about">About</NavLink>
</div>
</div>
</div>
</div>
);
};
export default MegaMenu;
This is Products component
import React, { Fragment, useEffect, useState } from "react";
import "./Products.css";
import { useSelector, useDispatch } from "react-redux";
import { clearErrors, getProduct } from "../../actions/productAction";
import Loader from "../layout/Loader/Loader";
import ProductCard from "../Home/ProductCard";
import Pagination from "react-js-pagination";
import Slider from "#material-ui/core/Slider";
import { useAlert } from "react-alert";
import Typography from "#material-ui/core/Typography";
import MetaData from "../layout/MetaData";
import { useParams } from "react-router";
import { NavLink, useLocation } from "react-router-dom"
const categories = [
"Sunglass",
"Footwear",
"Men Watch",
"Women Watch",
"Computer",
"SmartPhones",
"Camera",
];
const Products = ({ match }) => {
const dispatch = useDispatch();
const urlLocation = useLocation();
const categoryName = urlLocation.pathname.split('/')[2];
const alert = useAlert();
const [currentPage, setCurrentPage] = useState(1);
const [price, setPrice] = useState([0, 25000]);
// const [category, setCategory] = useState(categoryName);
const [category, setCategory] = useState('');
const [ratings, setRatings] = useState(0);
const {
products,
loading,
error,
productsCount,
resultPerPage,
filteredProductsCount,
} = useSelector((state) => state.products);
const keyword = match.params.keyword;
const setCurrentPageNo = (e) => {
setCurrentPage(e);
};
const priceHandler = (event, newPrice) => {
setPrice(newPrice);
};
let count = filteredProductsCount;
useEffect(() => {
if (error) {
alert.error(error);
dispatch(clearErrors());
}
dispatch(getProduct(keyword, currentPage, price, category, ratings));
}, [dispatch, keyword, currentPage, price, category, ratings, alert, error]);
return (
<Fragment>
{loading ? (
<Loader />
) : (
<Fragment>
<MetaData title="PRODUCTS -- ECOMMERCE" />
<h2 className="productsHeading">Products</h2>
<div className="products">
{products &&
products.map((product) => (
<ProductCard key={product._id} product={product} />
))}
</div>
<div className="filterBox">
<Typography>Price</Typography>
<Slider
value={price}
onChange={priceHandler}
valueLabelDisplay="auto"
aria-labelledby="range-slider"
min={0}
max={25000}
/>
<Typography>Categories</Typography>
<ul className="categoryBox">
{categories.map((category) => (
<li className="category-link" >
<NavLink style={{ textDecoration: 'none', color: 'black' }} key={category} onClick={() => setCategory(category)} to={`/products`}>{category}</NavLink>
</li>
))}
</ul>
<fieldset>
<Typography component="legend">Ratings Above</Typography>
<Slider
value={ratings}
onChange={(e, newRating) => {
setRatings(newRating);
}}
aria-labelledby="continuous-slider"
valueLabelDisplay="auto"
min={0}
max={5}
/>
</fieldset>
</div>
{resultPerPage < count && (
<div className="paginationBox">
<Pagination
activePage={currentPage}
itemsCountPerPage={resultPerPage}
totalItemsCount={productsCount}
onChange={setCurrentPageNo}
nextPageText="Next"
prevPageText="Prev"
firstPageText="1st"
lastPageText="Last"
itemClass="page-item"
linkClass="page-link"
activeClass="pageItemActive"
activeLinkClass="pageLinkActive"
/>
</div>
)}
</Fragment>
)}
</Fragment>
);
};
export default Products;
** When I want to click on the mega menu "Shop>>Category" name the URL would be like http://localhost:3000/products/Sunglass Here sunglass is the category name **
** Now I want to data update in the Product component (ProductCard Update) using the URL category part. But it does not work. **

Related

Displaying properties in another page when plus ( + )button is clicked in table

I have created react app. I have directory components with folder pages where I have FindAllMetadata component in which I am making GET request and getting all metadata from API. I am passing loadedMetadata to AllMetadataTable as props. AllMetadataTable component is located in other folder called data. There I am displaying some information about fetched metadata items in table ( Creator, Time Created, Format ) and other fetched properties I am not displaying. In a table aside of the every fetched metadata I have + button which when clicked makes link ( route ) to the new page where I want display all information about fetched metadata, single clicked metadata item. Details component is located in folder pages. I want to display clicked Metadata from AllMetadataTable in Details page or in Metadata component.
Here is my App.js :
import React, { Suspense } from 'react';
import { Switch, Route, BrowserRouter } from 'react-router-dom';
import classes from './App.module.css'
import LoadingSpinner from './components/UI/LoadingSpinner';
import Layout from './components/layout/Layout';
import Footer from './components/layout/Footer';
import RequestMenu from './components/UI/RequestMenu';
// load components only when user gets to them
const Dashboard = React.lazy(() => import('./components/pages/Dashboard'));
const NewData = React.lazy(() => import('./components/pages/NewData'));
const NotFound = React.lazy(() => import('./components/pages/NotFound'));
const FindAllReceivedRequests = React.lazy(() => import('./components/pages/FindAllReceivedRequests'));
const FindAllGivenConsents = React.lazy(() => import('./components/pages/FindAllGivenConsents'));
const ReadConsent = React.lazy(() => import('./components/pages/ReadConsent'));
const FindData = React.lazy(() => import('./components/pages/FindData'));
const FindAllMetadata = React.lazy(() => import ('./components/pages/FindAllMetadata'));
const NewPartnerRequest = React.lazy(() => import('./components/pages/NewPartnerRequest'));
const FindAllGivenRequests = React.lazy(() => import('./components/pages/FindAllGivenRequests'));
const FindAllReceivedConsents = React.lazy(() => import('./components/pages/FindAllReceivedConsents'));
const Metadata = React.lazy(() => import('./components/data/Metadata'));
function App() {
return (
<BrowserRouter>
<Layout>
<Suspense fallback= { <div className = { classes.centered }> <LoadingSpinner /> </div> } >
<Switch>
<Route path ='/' exact>
<Dashboard />
<FindData />
</Route>
<Route path= '/new-data' exact>
<NewData />
</Route>
<Route path= '/metadata' exact>
<FindAllMetadata />
</Route>
<Route path = '/data'>
<Metadata />
</Route>
<Route path= '/request' exact>
<RequestMenu />
<FindAllReceivedRequests />
<section style = {{ marginTop: '5rem',
}}>
<FindAllGivenConsents />
</section>
</Route>
<Route path= '/givenrequest' exact>
<RequestMenu />
<FindAllGivenRequests />
<section style = {{ marginTop: '5rem',
}}>
<FindAllReceivedConsents />
</section>
</Route>
<Route path= '/transfer-data' exact>
<ReadConsent />
</Route>
<Route path= '/partner-request' exact>
<NewPartnerRequest />
</Route>
<Route path= '*'>
<NotFound />
</Route>
</Switch>
</Suspense>
</Layout>
<Footer />
</BrowserRouter>
);
}
export default App;
Here is my FindAllMetadata.js where I am fetching allMetadata ( it is working ):
import React, { useState, useEffect, useMemo } from 'react';
import AllMetadataTable from '../data/AllMetadataTable';
import LoadingSpinner from '../UI/LoadingSpinner';
import styles from '../UI/Messages.module.css';
import styled from '../style/Form.module.css';
import { readAllMetadata } from '../lib/api';
const FindAllMetadata = () => {
const [allMetadata, setAllMetadata] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const [enteredMetadataFilter, setEnteredMetadataFilter] = useState('all');
// When page is loaded immediately fetch (and display) all metadata (only running the effect when enteredMetadataFilter changes)
useEffect(() => {
// fetch metadata by entered request filter (all or my)
const readAllMetadataHandler = async () => {
setIsLoading(true);
setError(null);
try {
const loadedAllMetadata = await readAllMetadata(enteredMetadataFilter);
setAllMetadata(loadedAllMetadata);
} catch (error) {
setError(error);
}
setIsLoading(false);
};
readAllMetadataHandler();
}, [enteredMetadataFilter]);
// display fetched content
const content = useMemo(() => {
if (error) {
return <div className={styles.negative}> { error.message } </div>;
} else if (isLoading) {
return <section style = {{margin : '1rem 17rem' }} ><LoadingSpinner /> </section>;
} else {
return (
<AllMetadataTable allMetadata = { allMetadata }
metadataFilter = { enteredMetadataFilter }
issLoading = { isLoading }
/>
);
}
}, [isLoading, error, allMetadata, enteredMetadataFilter]);
return (
<>
{/** pick filter for displaying metadata */}
{!isLoading &&
<section style= {{ marginLeft : '-10rem'}} >
<select className={styled.selectControl}
onChange={ event => {
setEnteredMetadataFilter(event.target.value);
}} >
<option value='' disabled style={{ color: '#cccccc' }} > Choose an option
</option>
<option value = 'all'> All Metadata </option>
<option value = 'my'> My Data </option>
</select>
</section>
}
<section>
{/**display content by status: error, loading, allmetadata, mymetadata */}
{ content }
</section>
</>
)
}
export default FindAllMetadata;
Here is my AllMetadataTable.js component where I am displaying fetched metadata in a table ( it is working and when I click + button it is redirecting me to correct URL ) :
import React from 'react';
import { Table, Button } from 'semantic-ui-react';
import "semantic-ui-css/components/table.min.css";
//import Metadata from './Metadata';
import classes from '../style/Form.module.css';
import Time from '../time/time';
import { useHistory } from 'react-router-dom';
import Metadata from './Metadata';
const AllMetadataTable = ({ allMetadata, metadataFilter, issLoading }) => {
const history = useHistory();
// sorted by time created - newest first
const allMetadataSorted = [...allMetadata].sort((a, b) => {
return new Date(b.TimestampCreated) - new Date(a.TimestampCreated);
});
// open details page for wanted metadata
const openDetailsPage = (key) => {
history.push({
pathname: 'data',
search: `?id=${allMetadata[key].DObjectId}`
})
};
return (
<>
{!issLoading &&
<Table celled fixed singleLine
style={{
width : '60rem',
marginLeft: '-10rem',
}} >
<Table.Header>
<Table.Row>
<Table.HeaderCell>Creator</Table.HeaderCell>
<Table.HeaderCell>Host</Table.HeaderCell>
<Table.HeaderCell>Domain</Table.HeaderCell>
<Table.HeaderCell>Format</Table.HeaderCell>
<Table.HeaderCell>Time Created</Table.HeaderCell>
<Table.HeaderCell
style={{
width : '4rem',
}}>Details</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{allMetadataSorted.map((metadata) => (
<React.Fragment key={metadata.key}>
<Table.Row>
<Table.Cell>{metadata.OrgIdCreator}</Table.Cell>
<Table.Cell>{metadata.OrgIdHost}</Table.Cell>
<Table.Cell>{metadata.TagsDomain}</Table.Cell>
<Table.Cell>{metadata.DataFormatId}</Table.Cell>
<Table.Cell>{Time(metadata.TimestampCreated)}</Table.Cell>
<Table.Cell>
{/** open/close metadata */}
<Button className={classes.uichange}
style ={{
border: 'none',
borderRadius: '0px',
color: 'white',
cursor: 'pointer',
backgroundColor: '#19a47c',
margin: '0 1rem',
fontSize : 22 }}
onClick={() => openDetailsPage(metadata.key) }>
+
</Button>
</Table.Cell>
</Table.Row>
</React.Fragment>
))}
</Table.Body>
</Table>
}
</>
);
};
export default AllMetadataTable;`
Here is my Metadata.js component which I wanna show in a new page when + button in a table is clicked ( id I am getting is corrrect and it is displaying in a list correctly but all other fields are empty; how can I access other fields and display them ?) :
`import React from 'react';
import classes from '../style/SingleData.module.css';
import list from '../style/List.module.css';
import { Button } from 'semantic-ui-react';
//import styles from '../UI/Messages.module.css';
import LoadingSpinner from '../UI/LoadingSpinner';
import Time from '../time/time';
import { useLocation } from 'react-router-dom';
/** import ORG_NAME */
const ORG = process.env.REACT_APP_ORG_NAME;
const Metadata = (props) => {
const { search } = useLocation();
const id = new URLSearchParams(search).get('id');
console.log(id);
// close metadata
const stopReadingDataHandler = () => {
props.onClose()
};
return (
<>
<ul className={list.tableList} >
<li style={{ borderRadius: '0px' }} className={classes.data}>
<strong> Data Id: </strong> {id}
</li>
<li style={{ borderRadius: '0px' }} className={classes.data}>
<strong> Doc Type Code: </strong> {props.DocTypeCode}
</li>
<li style={{ borderRadius: '0px' }} className={classes.data}>
<strong> Data Format: </strong> {props.DataFormatId}
</li>
<li style={{ borderRadius: '0px' }} className={classes.data}>
<strong>Creator: </strong> {props.OrgIdCreator}
</li>
<li style={{ borderRadius: '0px' }} className={classes.data}>
<strong> Host: </strong> {props.OrgIdHost}
</li>
<li style={{ borderRadius: '0px' }} className={classes.data}>
<strong>Tags Content: </strong> {props.TagsContent}
</li>
<li style={{ borderRadius: '0px' }} className={classes.data}>
<strong>Domain: </strong> {props.TagsDomain}
</li>
<li style={{ borderRadius: '0px' }} className={classes.data}>
<strong>Time Created: </strong> {Time(props.TimestampCreated)}
</li>
<li style={{ borderRadius: '0px' }} className={classes.data}>
<strong>Time Updated: </strong> {Time(props.TimestampUpdated)}
</li>
{ /** display Cancel button if you are Creator or Host */}
{!props.isLoading && (props.OrgIdCreator === ORG || props.OrgIdHost === ORG) && props.transferCheckStatus === false ?
<div style={{ justifyContent: 'flex-start' }}
className={classes.Form__actions}>
<Button className={classes.uichangedelete}
style ={{
border: 'none',
borderRadius: '3px',
color: 'white',
cursor: 'pointer',
backgroundColor: 'red',
margin: '10px',
fontSize : 22 }}
type= 'button'
content='Cancel'
onClick={ stopReadingDataHandler }
/>
</div>
: null }
{/** display loading spinner if loading */}
{props.isLoading && <LoadingSpinner />}
</ul>
</>
);
};
export default Metadata;
I tried using props inside FindAllMetadata, inside AllMetadataTable; I created other page Details.js in same folder as FindAllMetadata ( pages folder ) ; I tried useHistory, useLocation, useParams etc. `
In your openDetailsPage function you are passing only the id to the Metadata component:
const openDetailsPage = (key) => {
history.push({
pathname: 'data',
search: ?id=${allMetadata[key].DObjectId}
})
};
You are using history.push method with the following parameters:
pathname => which is '/data/ for Metadata component
search => query to url (NOTE: Here you are passing only the id)
Try adding:
state => an object to pass to the Metadata components:
history.push({
pathname: 'data',
search: `?id=${allMetadata[key].DObjectId}`,
state: {item: allMetadata[key]}
})
Then access it on the Metadata component by using:
props.location.state.item

How to prevent protected route re rendering?

import React, { useContext } from "react";
import { useLocation } from "react-router";
import { Navigate, Outlet } from "react-router-dom";
function ProtectedRoute({ children }) {
const location = useLocation();
const user = sessionStorage.getItem("userDetails");
console.log(location)
return user? (
children
) : (
<Navigate
to="/login"
replace
state={{
from: location,
}}
/>
);
}
export default ProtectedRoute;
The above code is for the protected route
import React, { useContext, useState } from "react";
import "./login.css";
import Image from "../../assests/images/login-image.jpeg";
import Person from "#mui/icons-material/Person";
import RemoveRedEyeSharp from "#mui/icons-material/RemoveRedEyeSharp";
import VisibilityOffSharp from "#mui/icons-material/VisibilityOffSharp";
import ArrowBackSharp from "#mui/icons-material/ArrowBackSharp";
import { UserDetails } from "../../App";
import { motion } from "framer-motion";
import FormError from "../formError/FormError";
import { HashLoader } from "react-spinners";
import baseUrl from "../../config/BaseUrl";
import axios from "axios";
import { useLocation, useNavigate, Link } from "react-router-dom";
function Login() {
const [showPassword, setShowPassword] = useState(false);
const [showError, setShowError] = useState(false);
const [userDetails, setUserDetails] = useContext(UserDetails);
const location = useLocation();
const navigate = useNavigate();
const [userForm, setUserForm] = useState({
username: "",
password: "",
});
const [message, setMessage] = useState("Default");
const [theme, setTheme] = useState("None");
const [loading, setLoading] = useState(false);
const handleShowPassword = () => {
setShowPassword(!showPassword);
};
const handleChange = (e) => {
const { name, value } = e.target;
setUserForm({ ...userForm, [name]: value });
};
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
const response = await axios.post(`${baseUrl}/user/login`, userForm);
sessionStorage.setItem("userDetails", JSON.stringify(response.data.user));
sessionStorage.setItem("token", JSON.stringify(response.data.token));
setUserDetails(response.data.user);
if(location.state?.from){
navigate(location.state.from)
}
else{
navigate("/")
}
setLoading(false);
} catch ({ response }) {
setMessage(response.data.message);
setTheme("loginError");
setShowError(true);
setLoading(false);
}
};
return (
<motion.div
className="loginBackground"
initial={{ opacity: 0 }}
animate={{
opacity: 1,
transition: {
duration: 0.15,
},
}}
exit={{
opacity: 0,
transition: {
duration: 0.15,
},
}}
>
<div className="loginForm">
{loading && (
<div className="loginLoading">
<HashLoader
color="#002db3"
loading={loading}
size={100}
></HashLoader>
</div>
)}
{!loading && (
<form className="loginFormInputs" onSubmit={handleSubmit}>
<div className="loginBack">
<ArrowBackSharp
style={{ fontSize: "1.7rem", cursor: "pointer" }}
onClick={() => navigate("/")}
></ArrowBackSharp>
</div>
<div className="loginFormHeader">
<div className="loginFormTitle">Welcome Back</div>
<div className="loginFormSubHeading">
Please login to your account to dive deep inside
</div>
</div>
<div className="loginFormInput">
<input
type="text"
name="username"
className="loginInput"
placeholder="Email"
required={true}
value={userForm.username}
onChange={handleChange}
/>
<Person></Person>
</div>
<div className="loginFormInput">
<input
type={showPassword ? "text" : "password"}
name="password"
className="loginInput"
spellCheck={false}
placeholder="Password"
required={true}
value={userForm.password}
onChange={handleChange}
/>
{showPassword ? (
<RemoveRedEyeSharp
onClick={handleShowPassword}
style={{ cursor: "pointer" }}
/>
) : (
<VisibilityOffSharp
onClick={handleShowPassword}
style={{ cursor: "pointer" }}
/>
)}
</div>
<div className="loginFormSubmit">
<button className="loginFormButton" type="submit">
Dive Deep
</button>
</div>
{showError && (
<FormError theme={theme} message={message}></FormError>
)}
<div className="loginFormSignUp">
Don't have an account?{" "}
<Link to={"/register"} style={{textDecoration:"none"}}>
<span
style={{
cursor: "pointer",
color: "blue",
fontWeight: "600",
fontSize: "1.1rem",
}}
>
Signup
</span>
</Link>
</div>
</form>
)}
<img src={Image} alt="img" className="loginImage" />
</div>
</motion.div>
);
}
export default Login;
This is the code snippet for the login component where the handle submit function is handling the redirect. Why is the protected route re-rendering twice? I tried removing the hooks and using session storage but still the protected route rendered twice and I can't understand why

Commerce JS, generateToken returning "Material-UI: A component is changing the controlled value state of Select to be uncontrolled."

This is where i generate the token
import React, { useState, useEffect } from 'react';
import { Paper, Stepper, Step, StepLabel, Typography, CircularProgress, Divider, Button } from '#material-ui/core';
import { commerce } from '../../../lib/commerce';
import useStyles from './styles';
import AddressForm from '../AddressForm';
import PaymentForm from '../PaymentForm';
const steps = ['Shipping address', 'Payment details'];
const Checkout = ({ cart }) => {
const [activeStep, setActiveStep] = useState(0);
const [checkoutToken, setCheckoutToken] = useState(null);
const classes = useStyles();
useEffect(() => {
if (cart.id) {
const generateToken = async () => {
try {
const token = await commerce.checkout.generateToken(cart.id, { type: 'cart' });
setCheckoutToken(token)
} catch (error){
console.log(error);
}
};
generateToken();
}
}, [cart]);
const Confirmation = () => (
<div>
Confirmation
</div>
)
const Form = () => activeStep === 0
? <AddressForm checkoutToken={checkoutToken} />
: <PaymentForm />
return (
<>
<div className={classes.toolbar} />
<main className={classes.layout} >
<Paper className={classes.paper}>
<Typography variant='h4' align='center'>Checkout</Typography>
<Stepper activeStep={activeStep} className={classes.stepper}>
{steps.map((step) => (
<Step key={step}>
<StepLabel>{step}</StepLabel>
</Step>
))}
</Stepper>
{activeStep === steps.length ? <Confirmation /> : checkoutToken && <Form />}
</Paper>
</main>
</>
)
}
export default Checkout
Here is my App.js
import React, { useState, useEffect, Fragment } from 'react'
import { commerce } from './lib/commerce';
import { Products, Navbar, Cart, Checkout } from './components';
import { BrowserRouter as Router, Routes, Route} from 'react-router-dom';
const App = () => {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState({});
const fetchProducts = async () => {
const { data } = await commerce.products.list();
setProducts(data);
}
const fetchCart = async () => {
setCart(await commerce.cart.retrieve())
}
const handleAddToCart = async ( productId, quantity) =>{
const { cart } = await commerce.cart.add(productId, quantity);
setCart(cart);
}
const handleUpdateCartQty = async (productId, quantity) => {
const { cart } = await commerce.cart.update(productId, { quantity });
setCart(cart);
}
const handleRemoveFromCart = async (productId) => {
const { cart } = await commerce.cart.remove(productId);
setCart(cart);
}
const handleEmptyCart = async () => {
const { cart } = await commerce.cart.empty();
setCart(cart);
}
useEffect(() => {
fetchProducts();
fetchCart();
}, []);
return (
<Router>
<div>
<Navbar totalItems={cart.total_items} />
<Routes>
<Route exact path='/' element={<Products products={products} onAddToCart={handleAddToCart} />} />
<Route exact path='/cart' element={<Cart cart={cart} handleUpdateCartQty={handleUpdateCartQty} handleAddToCart={handleAddToCart} handleRemoveFromCart={handleRemoveFromCart} handleEmptyCart={handleEmptyCart} />} />
<Route exact path='/checkout' element={ <Checkout cart={cart} />} />
</Routes>
</div>
</Router>
)
}
export default App;
And here is my cart.jsx incase their is anything relevant there
import React from 'react'
import { Container, Typography, Button, Grid} from '#material-ui/core';
import { Link } from 'react-router-dom';
import useStyles from './styles';
import CartItem from './CartItem/CartItem';
const Cart = ({ cart, handleUpdateCartQty, handleRemoveFromCart, handleEmptyCart }) => {
const classes = useStyles();
const EmptyCart = () => (
<Typography variant='subtitle1'>
You have no items in your shopping cart.
<Link to='/' className={classes.link}>Add Items!</Link>
</Typography>
);
const FilledCart = () => (
<>
<Grid container spacing={3}>
{ cart.line_items.map((item) => (
<Grid item xs={12} sm={4} key={item.id}>
<CartItem item={item} onUpdateCartQty={handleUpdateCartQty} onRemoveFromCart={handleRemoveFromCart} />
</Grid>
))}
</Grid>
<div className={classes.cardDetails}>
<Typography variant='h4'>
Subtotal: {cart.subtotal.formatted_with_symbol}
<div>
<Button className={classes.emptyButton} size='large' type='button' variant='contained' color='secondary' onClick={handleEmptyCart}>
Empty Cart
</Button>
<Button component={Link} to='/checkout' className={classes.checkoutButton} size='large' type='button' variant='contained' color='primary'>
Checkout
</Button>
</div>
</Typography>
</div>
</>
);
// Wait for cart to load items
if(!cart.line_items){
return '...loading';
}
return (
<Container>
<div className={classes.toolbar} />
<Typography className={classes.title} varaint='h3' gutterBottom >Your Shopping Cart</Typography>
{ !cart.line_items.length ? <EmptyCart /> : <FilledCart />}
</Container>
)
}
export default Cart
[error messages][1]
[1]: https://i.stack.imgur.com/vlard.png
Warning: Expected onSubmit listener to be a function, instead got a
value of string type. form
FormProvider#http://localhost:3000/static/js/bundle.js:76722:7
AddressForm#http://localhost:3000/static/js/bundle.js:1096:7 Form div
Paper#http://localhost:3000/static/js/bundle.js:12332:17
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 main
Checkout#http://localhost:3000/static/js/bundle.js:1332:7
Routes#http://localhost:3000/static/js/bundle.js:67209:7 div
Router#http://localhost:3000/static/js/bundle.js:67146:7
BrowserRouter#http://localhost:3000/static/js/bundle.js:65952:7
App#http://localhost:3000/static/js/bundle.js:347:82
Warning: A component is changing a controlled input to be
uncontrolled. This is likely caused by the value changing from a
defined to undefined, which should not happen. Decide between using a
controlled or uncontrolled input element for the lifetime of the
component. More info: https://reactjs.org/link/controlled-components
input SelectInput#http://localhost:3000/static/js/bundle.js:13482:19
div InputBase#http://localhost:3000/static/js/bundle.js:8257:25
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25
Input#http://localhost:3000/static/js/bundle.js:9146:26
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25
Select#http://localhost:3000/static/js/bundle.js:13182:26
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 div
Grid#http://localhost:3000/static/js/bundle.js:7352:29
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 div
Grid#http://localhost:3000/static/js/bundle.js:7352:29
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 form
FormProvider#http://localhost:3000/static/js/bundle.js:76722:7
AddressForm#http://localhost:3000/static/js/bundle.js:1096:7 Form div
Paper#http://localhost:3000/static/js/bundle.js:12332:17
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 main
Checkout#http://localhost:3000/static/js/bundle.js:1332:7
Routes#http://localhost:3000/static/js/bundle.js:67209:7

react link route not redirecting to url

I have this serch.js file. When I search and click on the li in the search result, I want to get redirected to <InnerDetail /> but the URL doesn't change or I don't get redirected to this page
but manualy if I type in the URL localhost/detiled/8 I am redirected to to <InnerDetail /> with id as 8
import React from "react";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faSearch } from "#fortawesome/free-solid-svg-icons";
import { useState, useEffect } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import { useHistory } from "react-router-dom";
const initialState = {
idaddProducts: "",
};
const Searchclients = () => {
const history = useHistory();
const [showResults, setShowResults] = React.useState(true);
const [poName, pnName] = React.useState(initialState);
const [showSerch, setShowSerch] = React.useState([]);
const [detail, setDetail] = useState(false);
const [inputValue, setInputValue] = React.useState("");
const [filteredSuggestions, setFilteredSuggestions] = React.useState([]);
const [selectedSuggestion, setSelectedSuggestion] = React.useState(0);
const [displaySuggestions, setDisplaySuggestions] = React.useState(false);
const suggestions = [];
showSerch.forEach(function (data) {
suggestions.push(data);
});
const onChange = (event) => {
const value = event.target.value;
setInputValue(value);
setShowResults(false);
const filteredSuggestions = suggestions.filter(
(suggestion) =>
suggestion.firstname
.toString()
.toLowerCase()
.includes(value.toLowerCase()) ||
suggestion.id.toString().toLowerCase().includes(value.toLowerCase())
);
setFilteredSuggestions(filteredSuggestions);
setDisplaySuggestions(true);
};
const onSelectSuggestion = (index) => {
setSelectedSuggestion(index);
setInputValue(filteredSuggestions[index]);
setFilteredSuggestions([]);
setDisplaySuggestions(false);
};
const SuggestionsList = (props) => {
// console.log(props);
const {
suggestions,
inputValue,
onSelectSuggestion,
displaySuggestions,
selectedSuggestion,
} = props;
if (inputValue && displaySuggestions) {
if (suggestions.length > 0) {
return (
<ul className="suggestions-list" style={styles.ulstyle}>
{suggestions.map((suggestion, index) => {
// console.log(suggestions);
const isSelected = selectedSuggestion === index;
const classname = `suggestion ${isSelected ? "selected" : ""}`;
return (
<Link to={`/detiled/${suggestion.id}`}> //this link dont work
<li
style={styles.listyle}
// onMouseOver={{ background: "yellow" }}
key={index}
className={classname}
>
{suggestion.firstname}
</li>
</Link>
);
})}
</ul>
);
} else {
return <div>No suggestions available...</div>;
}
}
return <></>;
};
useEffect(() => {
axios
.get("all-doctors-list/")
.then((res) => {
const data = res.data;
// pnName(data.data);
// var stringdata = data;
setShowSerch(data);
//console.log(stringdata);
});
// setShowSerch(data);
}, []);
return (
<>
<div className="note-container" style={styles.card}>
<div style={styles.inner}>
<p style={{ textAlign: "left" }}>Search Doctors</p>
<form className="search-form" style={{}}>
{showResults ? (
<FontAwesomeIcon
style={{ marginRight: "-23px" }}
icon={faSearch}
/>
) : null}
<input
onChange={onChange}
value={inputValue}
style={styles.input}
type="Search"
/>
<SuggestionsList
inputValue={inputValue}
selectedSuggestion={selectedSuggestion}
onSelectSuggestion={onSelectSuggestion}
displaySuggestions={displaySuggestions}
suggestions={filteredSuggestions}
/>
</form>
</div>
</div>
</>
);
};
export default Searchclients;
Navigator.js
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import InnerDetail from "./client/doctor/components/innerto_detail.js";
class Navigator extends React.Component {
render() {
return (
<Router>
<div>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/detiled/:id">
<InnerDetail />
</Route>
</Switch>
</div>
</Router>
);
}
}
function Home() {
return (
<div style={{ paddingTop: "20%", textAlign: "center" }}>
<h1>Home</h1>
</div>
);
}
export default Navigator;
when i hover on the<li> the bottom of the browser the path is showing currectly
i think the problem is here i tried another links here nothing is working here
<Link to={`/detiled/${suggestion.id}`}> //this link dont work
<li
style={styles.listyle}
// onMouseOver={{ background: "yellow" }}
key={index}
className={classname}
>
{suggestion.firstname}
</li>
</Link>
i tryed another link under the flowing code
a button called hello and that works i think the probelm is with the return
<SuggestionsList
inputValue={inputValue}
selectedSuggestion={selectedSuggestion}
onSelectSuggestion={onSelectSuggestion}
displaySuggestions={displaySuggestions}
suggestions={filteredSuggestions}
/>
<Link
to={{
pathname: `/detiled/5`,
}}
>
<button>hello</button>
</Link>
try using
<Route path="/detiled/:id" component={InnerDetail} />
instead of
<Route path="/detiled/:id">
<InnerDetail />`
in Navigator.js
and
Route exact path="/">
<Home />
did you created any Home component, and not imported that in Navigator.js
<Link to={"/detiled/"+ suggestion.id}><li>...</li></Link>
this worked for me

How to call a component from an onClick event

I would like to make it possible that whenever I click on a button (which is a component itself) a modal component is called. I did some research but none of the solutions is doing what I need. It partially works but not quite the way I want it to because, once the state is set to true and I modify the quantity in the Meals.js and click again the modal doesn't show up
Meals.js
import React, { useState } from "react";
import { Card } from "react-bootstrap";
import { Link } from "react-router-dom";
import NumericInput from "react-numeric-input";
import AddBtn from "./AddtoCartBTN";
function Meals({ product }) {
const [Food, setFood] = useState(0);
return (
<Card className="my-3 p-3 rounded">
<Link to={`/product/${product.id}`}>
<Card.Img src={product.image} />
</Link>
<Card.Body>
<Link to={`/product/${product.id}`} style={{ textDecoration: "none" }}>
<Card.Title as="div">
<strong>{product.name}</strong>
</Card.Title>
</Link>
Quantity{" "}
<NumericInput min={0} max={100} onChange={(value) => setFood(value)} />
{/* <NumericInput min={0} max={100} onChange={ChangeHandler(value)} /> */}
<Card.Text as="h6" style={{ color: "red" }}>
{Food === 0 ? product.price : Food * product.price} CFA
</Card.Text>
<AddBtn quantity={Food} price={product.price} productId={product.id} />
</Card.Body>
</Card>
);
}
export default Meals;
AddToCartBtn.js
import React, { useEffect, useState } from "react";
import { useDispatch } from "react-redux";
import { addToCart } from "../actions/cmdActions";
import toast, { Toaster } from "react-hot-toast";
import CartModal from "./CartModal";
function AddtoCartBTN({ quantity, price, productId }) {
const AddedPrice = quantity * price;
const [showModal, setShowModal] = useState(false)
const notify = () => toast("Ajout Effectue !", {});
const dispatch = useDispatch();
const AddtoCart = () => {
// console.log("Added to cart !");
// console.log("Added : ", AddedPrice);
if (AddedPrice > 0) {
dispatch(addToCart(productId, AddedPrice));
notify();
setShowModal(true)
}
};
return (
<button
className="btn btn-primary d-flex justify-content-center"
onClick={AddtoCart}
>
Ajouter
{showModal && <CartModal/>}
<Toaster />
</button>
);
}
export default AddtoCartBTN;
Modal.js
import React, { useState } from "react";
import { Modal, Button, Row, Col } from "react-bootstrap";
import { useSelector } from "react-redux";
import { useHistory } from "react-router-dom";
function CartModal () {
const [modalShow, setModalShow] = useState(true);
let history = useHistory();
const panierHandler = () => {
history.push('/commander')
}
const cart = useSelector((state) => state.cart);
const { cartItems } = cart;
function MyVerticallyCenteredModal(props) {
return (
<Modal
{...props}
size="md"
aria-labelledby="contained-modal-title-vcenter"
centered
backdrop="static"
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
<b style={{ color: "red" }}> choix de produits</b> <br />
</Modal.Title>
</Modal.Header>
<Modal.Body>
<Row>
<Col><b>Nom</b></Col>
<Col><b>Quantite</b></Col>
</Row><hr/>
{cartItems && cartItems.map((item,i)=>(
<>
<Row key={i}>
<Col>{item.name}</Col>
<Col>{item.total / item.price}</Col>
</Row><hr/>
</>
))}
</Modal.Body>
<Modal.Footer
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<Button
// onClick={props.onHide}
onClick={panierHandler}
>
Aller au Panier
</Button>
</Modal.Footer>
</Modal>
);
}
return (
<>
<MyVerticallyCenteredModal
show={modalShow}
onHide={() => setModalShow(false)}
/>
</>
);
}
export default CartModal
in AddToCartBtn.js, you can pass setShowModal as a prop.
{showModal && <CartModal setShowModal={setShowModal} />}
And the, in Modal.js, you can use the prop setShowModal to set the value to false
<MyVerticallyCenteredModal show={true} onHide={() => setShowModal(false)} />
Eliminate the state in Modal.js, keep visible as always true

Categories

Resources