I have a bootstrap navigation menu and I am trying to simulate a click of a nav item on a nav dropdown in React with Jest. I have the following dropdown:
Navbar.js
export default props => {
const { user, email, group } = props;
return (
<Nav className="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<button
type="button"
id="sidebarToggleTop"
className="btn btn-link d-md-none rounded-circle mr-3"
>
<FontAwesomeIcon icon={faBars} />
</button>
<ul className="navbar-nav ml-auto">
<div className="topbar-divider d-none d-sm-block" />
<NavDropdown
data-testid="profile-dropdown"
className="no-arrow"
title={
<>
<span className="mr-2 d-none d-lg-inline text-gray-600 small">
{user}
</span>
{email && (
<Gravatar
email={email}
className="img-profile rounded-circle"
/>
)}
</>
}
id="userDropdown"
>
<div className="dropdown-item">Profile: {group}</div>
<Link className="dropdown-item" to="/refresh">
Refresh
</Link>
<NavDropdown.Divider />
<NavDropdown.Item data-testid="sign-out-button" eventKey="logout" onSelect={() => Auth.signOut()}>
SignOut
</NavDropdown.Item>
</NavDropdown>
</ul>
</Nav>
);
};
Can anyone help? The item is not present in the DOM on render so I cannot use data-testid.
Related
i am trying to make a nav bar when a navlink is clicked i want the activelink to change background-color
i have used NavLink but it is not woeking for some reasome pls help
export class side extends Component {
render() {
return (
<div className="l-navbar " id="nav-bar">
<nav className="nav">
<NavLink
activeClassName="active3"
className="porpssidebar"
exact={true}
to="/"
>
<div>
<a href="#" className="nav_logo">
<img className="slogo" src={forur} />
<i className="fas fa-angry"></i>{" "}
</a>
</div>
</NavLink>
<NavLink activeClassName="active3" exact={true} to="/orders">
<div>
{" "}
<a href="#" className="nav_logo">
<Orders />
<i className="fas fa-angry"></i>{" "}
</a>
</div>
</NavLink>
<NavLink to="/customers" activeClassName="active3">
<div>
{" "}
<a href="#" className="nav_logo">
<Package />
<i className="fas fa-angry"></i>{" "}
</a>
</div>
</NavLink>
</div>
);
}
}
export default side;
in app.css i have a class called active3 for changing color
.active3 {
background: black;
}
On the homeScreen when you click a list of products, it goes the productScreen page with 1 product and its details.
When I added the onClick handler and onChange handler to the button and qty select in the productScreen.js, it causes it so that every time you go to productScreen (/products/:id) it will automatically redirect to /cart.
productScreen.js
import Rating from '../components/Rating'
import { useParams, Link } from 'react-router-dom'
import { useSelector, useDispatch} from 'react-redux'
import { useEffect, useState } from 'react'
import { productDetailCreator } from '../state/actions/productActions'
import { addCartAction } from '../state/actions/cartActions'
const ProductScreen = (props) => {
const { id } = useParams()
const dispatch = useDispatch()
const { loading, error, product } = useSelector(state => state.productDetail)
// Load Product
useEffect(() => {
dispatch(productDetailCreator(id))
}, [dispatch, id])
const [qty, setQty] = useState(0)
// Add to Cart Function
const addToCartHandler = (id, qty) => {
dispatch(addCartAction(id, qty))
props.history.push('/cart')
}
return (
<div className="max-w-5xl mx-auto my-36">
<div className=" mt-8 p-2">
<Link to="/" className="flex items-center text-gray-400 font-light">
<svg xmlns="http://www.w3.org/2000/svg" className="h-3 w-3 mr-1 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
</svg>
Back
</Link>
</div>
{ loading? (
<h3>Loading...</h3>
) : error ? (
<h3>{error}</h3>
) : (
<div className="flex flex-col sm:flex-row items-center my-7 px-8 py-2">
<div className="p-5 sm:w-2/5">
<img className="" src={product.image} alt={product.name} />
</div>
<div className="flex flex-col sm:w-2/5 p-5">
<span>{product.name}</span>
<hr className="my-4"/>
<Rating product={product} />
<hr className="my-4"/>
<span>Price: ${product.price}</span>
<hr className="my-4"/>
<span>Description: {product.description}</span>
</div>
<div className="flex flex-col sm:w-1/5 p-5">
<span className="text-center">Price: ${product.price}</span>
<span className="text-center mt-1">Status: {product.countInStock > 0 ? 'In Stock' : 'Out of Stock'}</span>
<div className="px-4 qty-select">
<label htmlFor="qty">Qty</label>
<select onChange={(e) => setQty(e.target.value)} name="qty" value="1" >
{ [...Array(10).keys()].map(x => (
<option value={x+1} key={x+1}>{x+1}</option>
))}
</select>
</div>
<button onClick={addToCartHandler(product._id, qty)} disabled={product.countInStock === 0} className="px-2 py-4 bg-pink-400 hover:bg-pink-300 hover:shadow-md text-white shadow-sm rounded-sm text-center my-4">Add to Cart</button>
</div>
</div>
)
}
</div>
)
}
export default ProductScreen
What's extremely weird is, if you click the image on the home page it will go to cart. If you click the product name on the home page, it will ADD the item to cart and go to cart.
There is no difference in the link references for either image or product name. I have no idea what's causing this issue?
Homescreen > product.js
import Rating from './Rating'
import {Link} from 'react-router-dom'
const Product = ({product}) => {
return (
<div className="card rounded shadow flex md:flex-col items-center overflow-hidden ">
<Link to={`/products/${product._id}`}>
<img className="mx-4 my-1 h-60 md:h-50 py-2 object-contain" src={product.image} alt={product.name} />
</Link>
<div className="py-4 px-4 mx-4 md:mx-2">
<Link to={`/products/${product._id}`} className="block h-28 font-light">{product.name}</Link>
<span className="block text-lg mb-4 font-medium">${product.price.toFixed()}</span>
<Rating product={product} />
<button className="px-6 py-4 my-4 min-w-full bg-pink-400 hover:bg-pink-300 hover:shadow-md text-white shadow-sm rounded-sm block">Add to Cart</button>
</div>
</div>
)
}
export default Product
All I know is if I get rid of the onClick on the Add to Cart button on productScreen.js, the redirect problem stops.
The way you set the onclick onClick={addToCartHandler(product._id, qty)} is calling the method immediately.
To prevent that you have to wrap it in an arrow function:
onclick={() => addToCartHandler(product._id, qty)}
Here you can see exactly your situation in the official docs
Here is some more info on sending params to the handler
I have three different Navbars. Each of them is a different component.
<PublicNavbar /> ,which is for public pages such as LandingPage, DiscoverPage etc.
<AccessNavbar /> ,which is for SignInPage, SignUppage, VerificationPage etc.
<PrivateNavbar /> , which is for private pages such as NewCampaignPage etc.
How can I show them properly? If a user is logged in, I want to replace DiscoverPage's PublicNavbar with PrivateNavbar.
import React from "react";
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import "semantic-ui-css/semantic.min.css";
import "./App.css";
import PublicNavbar from "./components/Navbar/PublicNavbar";
import AccessNavbar from "./components/Navbar/AccessNavbar";
import PrivateNavbar from "./components/Navbar/PrivateNavbar";
import Footer from "./components/Footer";
import LandingPage from "./pages/LandingPage";
import SignIn from "./pages/SIgnInPage";
import DiscoverPage from "./pages/DiscoverPage";
import SignUp from "./pages/SignUpPage";
import Verification from "./pages/VerificationPage";
import Registration from "./pages/RegistrationPage";
import RegistrationComplete from "./pages/RegistrationCompletePage";
import NewCampaign from "./pages/NewCampaignPage";
function App() {
return (
<Router>
<div>
<div id="container">
<div id="main">
<Switch>
<Route path="/" exact component={LandingPage} />
<Route path="/discover" component={DiscoverPage} />
<Route path="/signIn" component={SignIn} />
<Route path="/signUp" component={SignUp} />
<Route path="/verification" component={Verification} />
<Route path="/registration" component={Registration} />
<Route
path="/registration-complete"
component={RegistrationComplete}
/>
<Route path="/new-campaign" component={NewCampaign} />
</Switch>
</div>
</div>
<Footer />
</div>
</Router>
);
}
export default App;
Sample Navbar code:
import React from "react";
const PublicNavbar = () => {
return (
<nav className="navbar navbar-expand-lg bg-white">
<div className="container-fluid navbar-container">
<a className="navbar-brand abs nav-bar-title" href="#">
AshoDaanKori
</a>
<button
className="navbar-toggler ms-auto custom-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapseNavbar"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className="navbar-collapse collapse" id="collapseNavbar">
<ul className="navbar-nav ms-auto">
<li className="nav-item active">
<a
className="nav-link"
href=""
data-bs-target="#myModal"
data-bs-toggle="modal"
>
About
</a>
</li>
<li className="nav-item active">
<a
className="nav-link"
href=""
data-bs-target="#myModal"
data-bs-toggle="modal"
>
How it works
</a>
</li>
<li className="nav-item active">
<a
className="nav-link"
href=""
data-bs-target="#myModal"
data-bs-toggle="modal"
>
Discover
</a>
</li>
</ul>
<a
className="nav-link navbar-btn"
href=""
data-bs-target="#myModal"
data-bs-toggle="modal"
>
Start Campaign
</a>
</div>
</div>
</nav>
);
};
export default PublicNavbar;
Create a new Navbar component named something like NavBarController.
While calling the navbar controller component pass in the "Type" as prop. Type should be a state and should change depending on the user status.
<NavBarController type={1}></NavBarController>
Let NavBarController handle whichever navbar you want to display out of your three navbars
(where type will be 1,2 or 3).
Your NavBarController will return something like this:
return (props.type===1?<PublicNavbar/>
:props.type===2?<AccessNavbar/>
:props.type===3?<PrivateNavbar/>)
Solved it by conditional rendering. Without creating multiple Navbar components, I created one and changed the inner elements based on condition.
const Navbar = ({ isAuthenticated }) => {
return (
<nav
className={`autohide navbar navbar-expand-lg bg-white ${
isAuthenticated ? "private-navbar" : ""
}`}
>
<div className="container-fluid navbar-container">
<NavHashLink className="navbar-brand abs nav-bar-title" to="/">
AshoDaanKori
</NavHashLink>
<button
className="navbar-toggler ms-auto custom-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#main_nav"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
{isAuthenticated ? (
<div className="collapse navbar-collapse" id="main_nav">
<ul className="navbar-nav ms-auto">
<li className="nav-item active">
<NavHashLink to="/my-fundraisers" className="nav-link">
My fundraisers
</NavHashLink>
</li>
</ul>
<Link to="/start-campaign" className="nav-link navbar-btn">
Start a new campaign
</Link>
{/* User profile */}
<div className="btn-group nav-item">
<button
type="button"
className="btn "
data-bs-toggle="dropdown"
data-bs-display="static"
aria-expanded="false"
style={{ padding: "0" }}
>
<i aria-hidden="true" className="user circle huge icon"></i>
</button>
<ul className="dropdown-menu dropdown-menu-end">
<li>
<h3
style={{
textAlign: "center",
fontSize: 18,
fontWeight: 600,
color: "#6E6E6E",
}}
>
{userInfo.fullName || "User"}
</h3>
</li>
<li>
<hr className="dropdown-divider" />{" "}
</li>
<li>
<Link className="dropdown-item" to="/account">
Account Settings
</Link>
</li>
<li>
<Link
className="dropdown-item"
to="#"
>
Sign Out
</Link>
</li>
</ul>
</div>
</div> //If authenticated, rendered PrivateNavbar elements
) : (
<div className="collapse navbar-collapse" id="main_nav">
<ul className="navbar-nav ms-auto">
<li className="nav-item active">
<NavHashLink
smooth
to="/#our-story-section"
className="nav-link"
>
About
</NavHashLink>
</li>
<li className="nav-item active">
<NavHashLink to="/how-it-works" className="nav-link">
How it works
</NavHashLink>
</li>
<li className="nav-item active">
<NavHashLink to="/discover" className="nav-link">
Discover
</NavHashLink>
</li>
</ul>
<NavHashLink to="/sign-in" className="nav-link navbar-btn">
START CAMPAIGN
</NavHashLink>
</div> //If not authenticated, rendered PublicNavbar elements
)}
</div>
</nav>
);
};
export default Navbar;
I have this navbar where the user can navigate through the site and logged in users can make posts on the main page or news posts on the news page. However, i have 3 levels of permissions made in the backend where the visitors are allowed to navigate the website, then authenticated users can make normal posts or news posts but the last one is admin only permission to make a program post. the question is how can i show the third button (which is for program post) not show for authenticated users and only pop up when an admin logs in
these buttons can be found in the code bellow under authLinks
import { Link, NavLink } from 'react-router-dom';
import { connect } from 'react-redux';
import { logout } from '../actions/auth';
import Alert from './Alert';
import PropTypes from 'prop-types';
import {Navbar, NavDropdown} from "react-bootstrap";
import Logo from '../assets/images/logo.png';
const navbar = ({ auth:{isAuthenticated, loading}, logout}) => {
const authLinks = (
<Fragment>
<NavLink className='btn btn-primary btn-sm m-2' to='/create-post'>Nytt innlegg</NavLink>
<NavLink className='btn btn-primary btn-sm m-2' to='/create-nyhet'>Nytt nyhetsinnlegg</NavLink>
<NavLink className='btn btn-primary btn-sm m-2' to='/create-program'>Nytt arrangement</NavLink>
<a className='btn btn-primary btn-sm m-2' onClick={logout} href='#!'>Logg ut</a>
</Fragment>
);
const guestLinks = (
<NavLink className='btn btn-primary btn-sm m-2' to='/login'>Logg inn</NavLink>
);
return(
<Fragment>
<Navbar bg="dark" variant="dark" expand="md" sticky="top">
<div className="container-fluid">
<Navbar.Brand href='/'><img className="img-responsive" src={Logo} width="220" height="55" alt="Sammfunnet Logo" /></Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<ul className="navbar-nav p-2">
<li className="nav-item active">
<NavLink className="nav-link" exact to='/'>Hjem</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" exact to='/nyhet'>Nyhet</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" exact to='/program'>Program</NavLink>
</li>
<NavDropdown title="Kontakt Oss" id="basic-nav-dropdown">
<NavDropdown.Item href="/bli-frivillig">Bli Frivillig</NavDropdown.Item>
<NavDropdown.Item href="/presse">Presse</NavDropdown.Item>
<NavDropdown.Item href="#action/3.3">Samarbeid</NavDropdown.Item>
</NavDropdown>
<li className="nav-item">
<NavLink className="nav-link" exact to='/omoss'>Om oss</NavLink>
</li>
</ul>
</Navbar.Collapse>
<span className="nav_link">
{ !loading && (<Fragment>{ isAuthenticated ? authLinks : guestLinks }</Fragment>) }
</span>
</div>
</Navbar>
<Alert />
</Fragment>
);
};
navbar.propTypes = {
logout: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired
}
const mapStateToProps = state => ({
auth: state.auth
});
export default connect(mapStateToProps, { logout })(navbar);
Do this then should work
const authLinks = (
<Fragment>
<NavLink className='btn btn-primary btn-sm m-2' to='/create-post'>Nytt innlegg</NavLink>
<NavLink className='btn btn-primary btn-sm m-2' to='/create-nyhet'>Nytt nyhetsinnlegg</NavLink>
{ isAuthenticated && (<NavLink className='btn btn-primary btn-sm m-2' to='/create-program'>Nytt arrangement</NavLink> ) }
<a className='btn btn-primary btn-sm m-2' onClick={logout} href='#!'>Logg ut</a>
</Fragment>
);
This is my code for the queue please only answer if you personally know me and are fimiliar with the project.
import React, { Fragment } from 'react';
import { Link } from 'react-router-dom'
import InputQ from './InputQ';
import ListQ from './ListQ';
import './Admin.css';
const AdminQueue = () => {
return (
<Fragment>
<InputQ />
<Link to="/">
<i className="fas fa-home float-right mt-3 mb-3" aria-hidden="true" />
</Link>
<Link to="/signin">
<i className="fa fa-lock float-right mt-3 mb-3 mr-3" aria-hidden="true" />
</Link>
<ListQ />
</Fragment>
)
}
export default AdminQueue;
All you have to do is import this make sure download with npm:
import SGF from 'react-sgf-dom';
And Wrap what you want to SGF with the tags:
const AdminQueue = () => {
return (
<SGF>
<InputQ />
<Link to="/">
<i className="fas fa-home float-right mt-3 mb-3" aria-hidden="true" />
</Link>
<Link to="/signin">
<i className="fa fa-lock float-right mt-3 mb-3 mr-3" aria-hidden="true" />
</Link>
<ListQ />
</SGF>
)
}