Problem with row-alignment using React & Bootstrap GRID system - reactjs

Using React.JS and BootStrap grid system, I'm aiming to build the following page.
However, with the code linked at the bottom, the page looks like this (the alignment of the elements is wrong in multiple places. For example, the banner and search bar aren't aligned with the rest of the elements.
What am I doing wrong in using the BootStrap Grid System?
Before that, I'd like to specify that all the 4 MinWidget.jsx components are wrapped inside a MinWidgetCollection.jsx component. And all the elements encompased by the red border are wrapped inside a PageInformation.jsx component. The MiniWidgetCollection must take 7/12 of the page width while the BigWidget one the rest of 5/12 (with BootStrap grid having a maximum of 12 columns per row). Similarly, the first chart below must have 7/12 of width while the second chart only 5/12.
This is the current code which produces errors in alignment.
function App() {
return (
<div className='container'>
<Searchbar/>
<Banner/>
<PageInformation/>
</div>
)
}
export const Searchbar = (props) => {
return (
<div className='row mb-5' style={{border: "1px solid green"}}>
<div className='card-header p-7 w-50'>
</div>
)
export const Banner = (props) => {
return (
<div className='row'>
<div className='card mb-5 mb-xl-10'>
</div>
</div>
)
export const PageInformation = (props) => {
return (
<div style={{border: "1px solid red"}}>
<div className='row'>
<MinWidgetCollection />
<BigWidget />
</div>
<div className='row'>
<Chart newClassname='col-md-7 col-xs-12' />
<Chart newClassname='col-md-5 col-xs-12' />
</div>
</div>
)
}
export const MinWidgetCollection = (props) => {
return (
<div className='row col-md-7 col-xs-12'>
<MinWidget />
<MinWidget />
<MinWidget />
<MinWidget />
</div>
)
}
export const MinWidget = (props) => {
return (
<div className='col-md-6 col-xs-12'>
<div className='card card-md-6 card-xs-12 mb-xl-8'>
</div>
</div>
)
}
export const BigWidget = (props) => {
return (
<div className='col-md-5 col-xs-12'>
<div className="card card-xl-stretch mb-5 mb-xl-8 h-100">
</div>
</div>
)
}
export const Chart = (props) => {
<div className={props.newClassname}>
<div className={`card mt-5 `}>
</div>
</div>
}

Related

Unable to load pdf in react

I'm trying to load a pdf file for the user in another tab once they click a button but it's not working and I'm not sure how to make it work. Could I have some help in doing this?
I defined a function PdfViewer() and I call it when a button is clicked using onClick(), but once the button is clicked I get this error:
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
Here's my code:
import "../styles/ProjectDetails.css";
import React, { useState } from 'react'
import { Document, Page } from 'react-pdf/dist/esm/entry.webpack'
function PdfViewer() {
const [numPage, setNumPages] = useState(null);
const [pageNumber, setPageNumber] = useState(1);
function onDocumentLoadSuccess({numPages}) {
setNumPages(numPage);
setPageNumber(1);
}
return (
<div>
<header>
<Document file="../pdfs/Mini_Case_Study_15.pdf" onLoadSuccess={onDocumentLoadSuccess}>
<Page height="600" pageNumber={pageNumber}></Page>
</Document>
</header>
</div>
)
}
const ProjectDetails = ({ project }) => {
return (
<div className="card-grid">
<div className="card">
<div className="card-header card-image">
<img src="https://c4.wallpaperflare.com/wallpaper/672/357/220/road-background-color-hd-wallpaper-thumb.jpg"/>
</div>
<div className="card-title"><strong>{project.sdg}</strong></div>
<div className="card-body">
<strong>Goal:</strong> {project.goal}
</div>
<div className="card-themes">
<strong>Themes:</strong> {project.theme.map((theme)=>{return theme + ', '})}
</div>
<div className="card-assignment">
<strong>Assignment Type:</strong> {project.assignment_type}
</div>
<div className="card-footer">
<button className="btn">Details</button>
{project.assignment_type === 'Mini Case Studies' &&
<>
<button className="btn btn-outline">Download</button>
{/* <button onClick={PdfViewer} className="btn">Preview</button> */}
</>
}
</div>
</div>
</div>
)
}
export default ProjectDetails
How do I make it so that once the user clicks the button, it takes them to another page with the pdf file shown?
You could try this approach here, inserting the Preview as a Component.
const ProjectDetails = ({ project }) => {
const [preview, setPreview] = useState(false)
const onClickToPreviewPDF = () => {
setPreview(preview ? false : true);
}
return (
<>
<div className="card-grid">
<div className="card">
<div className="card-header card-image">
<img src="https://c4.wallpaperflare.com/wallpaper/672/357/220/road-background-color-hd-wallpaper-thumb.jpg"/>
</div>
<div className="card-title"><strong>{project.sdg}</strong></div>
<div className="card-body">
<strong>Goal:</strong> {project.goal}
</div>
<div className="card-themes">
<strong>Themes:</strong> {project.theme.map((theme)=>{return theme + ', '})}
</div>
<div className="card-assignment">
<strong>Assignment Type:</strong> {project.assignment_type}
</div>
<div className="card-footer">
<button className="btn">Details</button>
{project.assignment_type === 'Mini Case Studies' &&
<>
<button className="btn btn-outline">Download</button>
<button onClick={onClickToPreviewPDF} className="btn">Preview</button>
</>
}
</div>
</div>
</div>
{preview && <PdfViewer />}
</>
)
}

How to pass props to a component on clicking button?

I have displayed all the anime images from api, now I want if any anime result is clicked then it should open details for that particular anime. I have created component Details where I want to send details of anime.
how can I send details of anime to the component Details ?
Here is my code:
import { useEffect, useState } from 'react';
import './CSS/style.css';
import Details from './components/Details';
function App() {
const [user, setUser] = useState([])
const getUsers = async () =>{
const response = await fetch('https://ghibliapi.herokuapp.com/films')
setUser(await response.json());
}
useEffect(() => {
getUsers();
}, []);
const getDetail = (e) =>{
// what should I write here to pass props on component < Details />
console.log(e)
}
return (
<>
<h2>Anime World</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
{
user.map((curElem) => {
return (
<div className="col-10 col-md-4 mt-5" key={curElem.id} >
<div className="card">
<img src={curElem.image} className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<h5 className="card-title">{curElem.title} </h5>
<button onClick={getDetail} >Get Detail</button>
</div>
</div>
</div>
)
})
}
</div>
</div>
</>
);
}
export default App;
Dummy values are given to component Details right now, I have to get correct value from props.
import React from 'react';
import './details.css';
function Details() {
return (
<>
<h2>Information of Anime</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
<div className="col-10 col-md-8 mx-auto" >
<div className="card box">
<img src= '...' className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<div className='details'>
<h5><span>Title:</span> Title</h5>
<h5><span>Original Title:</span> Original Title</h5>
<h5><span>Director:</span> Director</h5>
<h5><span>Producer:</span> Producer</h5>
<h5><span>Release Date:</span> date</h5>
<h5><span>Running time:</span> time</h5>
<h5><span>Description:</span> <p> Description</p></h5>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default Details;
I'm going to assume that the list you receive from the API is the list of each anime, and when you click you want to render the selected anime using the Details component. If that's the case this is my approach
import { useEffect, useState } from 'react';
import './CSS/style.css';
import Details from './components/Details';
function App() {
const [user, setUser] = useState([]);
const [anime, setAnime] = useState(null);
const getUsers = async () =>{
const response = await fetch('https://ghibliapi.herokuapp.com/films');
setUser(await response.json());
};
useEffect(() => {
getUsers();
}, []);
const getDetail = (anime) =>{
setAnime(anime);
};
return (
<>
<h2>Anime World</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
{user.map((elem) => (
<div className="col-10 col-md-4 mt-5" key={curElem.id}>
<div className="card">
<img src={elem.image} className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<h5 className="card-title">{elem.title} </h5>
<button onClick={() => getDetail(elem)} >Get Detail</button>
</div>
</div>
</div>
))}
</div>
</div>
{anime && <Details {...anime} />}
</>
);
}
export default App;
So basically what I'm doing here is rendering <Details /> only when an anime element is in state. If it's null it won't render the component.
Secondly I'm spreading the selected element into the Details component, so that inside the component you can access each property like this:
import React from 'react';
import './details.css';
function Details(props) {
const { title } = props; // each prop is each property of the selected anime
return (
<>
<h2>Information of Anime</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
<div className="col-10 col-md-8 mx-auto" >
<div className="card box">
<img src= '...' className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<div className='details'>
<h5><span>Title:</span> {title}</h5>
<h5><span>Original Title:</span> Original Title</h5>
<h5><span>Director:</span> Director</h5>
<h5><span>Producer:</span> Producer</h5>
<h5><span>Release Date:</span> date</h5>
<h5><span>Running time:</span> time</h5>
<h5><span>Description:</span> <p> Description</p></h5>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default Details;

Button Flickering onHover in React

I have 2 Components "TableCard" et "TableGrouping". I have a component inside "TableCard" called "Grouping".
When I hover the button with my mouse it is flickering/flashing on my screen. The 2 components are separated in 2 files because I need to modify the content of "TableGrouping" in "TableCard" (when I put directly the content of grouping into "TableGrouping" it's working fine but it's not my objective.
Here is my code:
export function TableGrouping(props) {
return (
<div className="form">
<div className="row align-items-center form-group-actions margin-top-20 margin-bottom-20">
<div className="col-xl-12">
<div className="form-group form-group-inline">
<div className="form-label form-label-no-wrap">
{props.children}
</div>
</div>
</div>
</div>
</div>
);
}
export function TableCard() {
const Grouping = () => {
function BtnSupprimer(props) {
return <Button>test</Button>;
}
return (
<>
<BtnSupprimer/>
</>
);
};
return (
<TableGrouping>
<Grouping />
</TableGrouping>
);
}
Link of what it's doing : here
Do some of you have an Idea ? Thank you :)

Button Click to Render Div

I want to click the button and render its corresponding div. Should I add the the div's info that I want to render to the state?
I'm sure there's a few different ways to solve this but I want to do it the React way and maybe as a function component?
Updated
export default function About(props) (
const [isHidden, setIsHidden] = useState(true);
const handleClick = () => {
setIsHidden(!isHidden);
};
return (
<div className="row justify-content-md-center">
<div className="col-auto">
<CustomButton onClick={handleClick}>Website Develpment</CustomButton>
</div>
<div className="col-auto">
<CustomButton onClick={handleClick}>Wordpress Develpment</CustomButton>
</div>
<div className="col-auto">
<CustomButton onClick={handleClick}>Ecommerce Development</CustomButton>
</div>
</div>
<div className="row">
<div className="col-md-4">column 1</div>
<div className="col-md-4">column 2</div>
<div className="col-md-4">column 3</div>
</div>
);
)
You can store an ID as a string state variable, and set that variable on button press.
Then use ConditionalRendering to only display the div with the matching ID.
const {useState} = React;
function About(props) {
const [visibleItem, setVisibleItem] = useState('');
return (
<div>
<button onClick={() => setVisibleItem("website")}>
Show Website Develpment
</button>
<button onClick={() => setVisibleItem("wordpress")}>
Show Wordpress Develpment
</button>
<button onClick={() => setVisibleItem("ecommerce")}>
Show Ecommerce Development
</button>
{visibleItem === "website" &&
<div>
<h2>Wordpress Development</h2>
<p>Info about Wordpress and all the things I can do with it</p>
</div>
}
{visibleItem === "wordpress" &&
<div>
<h2>Ecommerce Development</h2>
<p>I can do eccomerce things too</p>
</div>
}
{visibleItem === "ecommerce" &&
<div>
<h2>Website Development</h2>
<p>Info about Webdev</p>
</div>
}
</div>
);
}
ReactDOM.render(
<About/>,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
If the sections were much bigger then I'd recommend splitting them out into separate components, or maybe doing an if or switch statement to select between them before the return, but the above snippet is a pattern I have used often with react.
You can create two states one holding array of button info to minimize repetition of code and another state to track the column clicked.
import React, { useState } from "react";
export default function About(props) {
const [colNum, setColNum] = useState('');
const [btnNames] = useState([
{
colId: 1,
name: "Website Develpment"
},
{
colId: 2,
name: "Wordpress Develpment"
},
{
colId: 3,
name: "Ecommerce Develpment"
}
]);
const handleClick = (id) => {
setColNum(id);
};
return (
<>
<div className="row justify-content-md-center">
{btnNames.map(element => (
<div className="col-auto" key={element.colId}>
<CustomButton onClick={()=> handleClick(element.colId)}>{element.name}</CustomButton>
</div>
))}
</div>
{colNum !== '' ? (<div className="row">
<div className="col-md-4">column {colNum}</div>
</div>) : null }
</>
);
}
So you can define showing value for each section in state, which initial should be false. Then we can handle this state with a function where built-in JS tools can be used (Object.entries, Object.fromEntries and map). The element will be displayed, the value of which will be true, and the rest will automatically become false. More details can be found here: https://codesandbox.io/s/happy-sea-nckmw?file=/src/App.js
import React, { useState } from "react";
import "./styles.css";
import styles from "./TestStyles.module.css";
import CustomButton from "./CustomButton";
export default function App() {
const [showDiv, setShowDiv] = useState({
web: false,
wordpress: false,
ecommerce: false
});
const showDivHandler = (val) => {
const newState = Object.fromEntries(
Object.entries(showDiv).map(([key, value]) => [key, (value = false)])
);
setShowDiv({
...newState,
[val]: !showDiv[val]
});
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<div className={styles.Section}>
<div className="col-auto">
<CustomButton clicked={() => showDivHandler("web")}>
Website Develpment
</CustomButton>
</div>
<div className="col-auto">
<CustomButton clicked={() => showDivHandler("wordpress")}>
Wordpress Develpment
</CustomButton>
</div>
<div className="col-auto">
<CustomButton clicked={() => showDivHandler("ecommerce")}>
Ecommerce Development
</CustomButton>
</div>
</div>
<div className={styles.Section} style={{marginTop: 20}}>
{showDiv.web && <div className={styles.Content}>column 1</div>}
{showDiv.wordpress && <div className={styles.Content}>column 2</div>}
{showDiv.ecommerce && <div className={styles.Content}>column 3</div>}
</div>
</div>
);
}
The custom button can look like this:
import React from "react";
const button = (props) => (
<button
onClick={props.clicked}
//some other props if need it(e.g. styles)
>
{props.children}
</button>
);
export default button;
This is how I solved it. Thanks for your help!
export default function About() {
const [visibleItem, setVisibleItem] = useState(1);
const [priceItems] = useState([
{
id: 1,
name: "website",
},
{
id: 2,
name: "wordpress",
},
{
id: 3,
name: "ecommerce",
},
]);
const handleClick = (id) => {
setVisibleItem(id);
};
return (
<div className="container-fluid pricing-wrapper">
<div className="row">
<div className="col">
<h1>Pricing</h1>
</div>
</div>
<div className="row">
<div className="col">
<p>Innovation that empowers your team while also reducing risk!</p>
<div className="seperator"></div>
</div>
</div>
<div className="row justify-content-md-center">
<div className="row justify-content-md-center">
{priceItems.map((item) => (
<div className="col-auto">
<CustomButton onClick={() => setVisibleItem(item.id)}>
{item.name}
</CustomButton>
</div>
))}
</div>
</div>
{priceItems
.filter((item) => item.id === visibleItem)
.map((item) => (
<PriceItem item={item} />
))}
</div>
);
}

hover over cards with React using the useref hook

I have used a useRef hook so that when I mouseover to particular card then the opacity of the other card becomes 0.4 I have a figure out a solution to this but I am thinking this might not be best solution and its quite lengthy too. Feel free to recommend me best solution regarding this. Here is my code and i have used bootstrap to create the card.
import React, { useRef } from 'react'
export default function Cardss() {
const cardOne = useRef();
const cardTwo = useRef();
const cardThree = useRef();
const mouseOverOpacityForCardOne = (e) => {
cardTwo.current.style.opacity = "0.4";
cardThree.current.style.opacity = "0.4";
}
const mouseOutOpacityForCardOne = (e) => {
cardTwo.current.style.opacity = "1";
cardThree.current.style.opacity = "1";
}
const mouseOverOpacityForCardTwo = (e) => {
cardOne.current.style.opacity = "0.4";
cardThree.current.style.opacity = "0.4";
}
const mouseOutOpacityForCardTwo = (e) => {
cardOne.current.style.opacity = "1";
cardThree.current.style.opacity = "1";
}
const mouseOverOpacityForCardThree = (e) => {
cardOne.current.style.opacity = "0.4";
cardTwo.current.style.opacity = "0.4";
}
const mouseOutOpacityForCardThree = (e) => {
cardOne.current.style.opacity = "1";
cardTwo.current.style.opacity = "1";
}
return (
<section className="container-fluid section-three">
<h2 className="display-3">Projects</h2>
<div className="row">
<div ref={cardOne} onMouseOver={mouseOverOpacityForCardOne} onMouseOut={mouseOutOpacityForCardOne} className={"col-md-4 col-12 mb-5"}>
<div className="card cards">
<img className="card-img-top" src="..." alt="Card image cap"/>
<div className="card-body">
<h5 className="card-title">Special title treatment</h5>
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
</div>
</div>
</div>
<div ref={cardTwo} className={"col-md-4 col-12 mb-5"} onMouseOver={mouseOverOpacityForCardTwo} onMouseOut={mouseOutOpacityForCardTwo}>
<div className="card cards">
<img className="card-img-top" src="..." alt="Card image cap"/>
<div className="card-body">
<h5 className="card-title">Special title treatment</h5>
<p className="card-text">With supporting text below as a natural lead-in to additional content.</p>
</div>
</div>
</div>
<div ref={cardThree} onMouseOver={mouseOverOpacityForCardThree} onMouseOut={mouseOutOpacityForCardThree} className={"col-md-4 col-12 mb-5"}>
<div className="card cards">
<img className="card-img-top" src="..." alt="Card image cap"/>
<div className="card-body">
<h5 className="card-title">Special title treatment</h5>
<p className="card-text">With supporting text below as a natural lead-in to additional content.</p>
</div>
</div>
</div>
</div>
</section>
)
}
You can accomplish using a combination of state variables and onMouseOver and onMouseLeave props.
Essentially, when the mouse is over a card, you store its index in the state variable, then have the class of the card be dynamic such that any index not equal to the state variable gets a class that applies the opacity: 0.4 to that card.
Here's a Codepen example illustrating this. I used opacity: 0.2 instead
To make the code less lengthy, let's first turn a card into a component.
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
const Card = ({ // I'm using default parameters here
imageSrc = "https://source.unsplash.com/random/400x400",
title = "Special title treatment",
text = "With supporting text below as a natural lead-in to additional content.",
...props // pass the rest props to the wrapping div
}) => (
<div {...props}>
<div className="card cards">
<img className="card-img-top" src={imageSrc} alt="Unsplash Random" />
<div className="card-body">
<h5 className="card-title">{title}</h5>
<p className="card-text">{text}</p>
</div>
</div>
</div>
);
Then, to achieve the opacity change, you can track the active card (the one with mouse over) with state and apply CSS classes to style the cards:
// Cards.js
function Cards() {
const [active, setActive] = useState(-1); // I'm using -1 to indicate no active cards
const getCardClassName = index => {
if (active > -1 && index !== active) return "fadeOut";
return "";
};
return (
<section
className="container-fluid section-three"
>
<h2 className="display-3">Projects</h2>
<div className="row">
{[0, 1, 2].map(i => ( // or [...Array(3).keys()].map
<Card
key={i}
className={`col-md-4 col-12 mb-5 ${getCardClassName(i)}`}
onMouseOver={() => {
setActive(i);
}}
onMouseOut={() => {
setActive(-1);
}}
/>
))}
</div>
</section>
);
}
// style.css
.fadeOut {
opacity: 0.4;
}
Here is a working example:

Resources