React Bootstrap Card Result in Multiple Columns - node.js

Below is my code, my problem is, the results are displaying at the bottom one by one like this:
1
2
3
I want to display each output result as follows? as 3 column
1 2 3
4 5 so on......
I have used https://react-bootstrap.github.io/components/cards/ component to display the database output
{Mylist.length && Mylist.map((item, index) => {
return (
<Card key={index} style={{ width: '18rem' }}>
<Card.Body>
<Card.Subtitle className="mb-2 text-muted">{moment(item.date_time).format('LLL')}</Card.Subtitle>
<Card.Text>{item.content}</Card.Text>
<Button variant="danger" size="sm" data-id={item.id} onClick={() => remove(item.id)} >Delete</Button>{' '}
</Card.Body>
</Card>
)
})}

Try the following approach, see more at https://react-bootstrap.netlify.app/components/cards/#card-groups
<Row xs={1} md={2} className="g-3">
{Mylist.length && Mylist.map((item, index) => {
return (
<Col key={index}>
<Card style={{ width: '18rem' }}>
<Card.Body>
<Card.Subtitle className="mb-2 text-muted">{moment(item.date_time).format('LLL')}</Card.Subtitle>
<Card.Text>{item.content}</Card.Text>
<Button variant="danger" size="sm" data-id={item.id} onClick={() => remove(item.id)} >Delete</Button>{' '}
</Card.Body>
</Card>
</Col>
)
})}
</Row>

Related

React Route to Page Using Unique ID

I have multiple rendered components on a page. When I click on one I want to navigate to a new page with all of the information specific to that component. What I need is:
OnClick -> Identify gameId variable
Using that gameID run a query against an API endpoint
Take the rendered data from the API and display it on a new page with route /nhl/:gameId
Example screenshot of /NHL page with different components.
/NHL Route
I have this existing Scores component:
function Scores(props) {
const navigate = useNavigate('/');
const handleClick = () => {
let path = '/' + {gameId};
navigate(path);
}
return (
<Card sx={{ Height: 50, padding: .25, margin: 3 }}>
<CardActionArea onClick={handleClick}>
<div className = "">
<CardContent sx={{ width: 200 }}>
<Stack direction="row" spacing={2}>
<Typography component="div" variant="h6">{props.gameStatus}</Typography>
<Typography>{props.gameDateandTime}</Typography>
</Stack>
<Stack direction="row" spacing={2}>
<Typography fontSize={14} sx={{ paddingTop: 1, paddingBottom: 1 }}>{props.awayTeam}</Typography>
<Typography fontSize={14} sx={{ paddingTop: 1, paddingBottom: 1 }}>{props.awayPoints}</Typography>
</Stack>
<Typography>#</Typography>
<Stack direction="row" spacing={2}>
<Typography fontSize={14} sx={{ paddingTop: 1, paddingBottom: 1 }}>{props.homeTeam}</Typography>
<Typography fontSize={14} sx={{ paddingTop: 1, paddingBottom: 1 }}>{props.homePoints}</Typography>
</Stack>
</CardContent>
</div>
</CardActionArea>
</Card>
)
}
export default Scores;
The Scores.js component above is rendered in the NHL route from the screenshot:
function NHL(){
var date = year + "-" + month + "-" + day;
const [scores, setScores] = useState([{ }]);
useEffect(() => {
let url = "http://localhost:3001/schednhl";
fetch(url).then(res => {
if(res.ok) {
return res.json()
}
}).then(jsonRes => setScores(jsonRes));
}, []);
return (
<div className='Home'>
<Banner />
<Typography variant="h3" align="center" sx={{ paddingTop: 5 }}>Live Games</Typography>
<hr className="lineRow"></hr>
<Stack direction="row" spacing={2}>
<div className="scroll-box">
<div className="scroll-box-wrapper">
<div className="scroll-box-container" role="list">
{scores.map((score, index) => {
if(score.gameDate === date && score.gameStatus === "closed" || score.gameStatus === "inprogress")
return (
<Scores
className="scroll-box-item"
role="listitem"
key={index}
id={index}
gameDate={score.gameDate}
gameStatus={score.gameStatus === "closed" ? "Final" : "Live" }
homeTeam={score.homeTeam}
homePoints={score.homePoints}
awayPoints={score.awayPoints}
awayTeam={score.awayTeam}
/>
);
})}
</div>
</div>
</div>
</Stack>
<h3 className="home-header" style={{paddingTop: 10 }}>Upcoming Games</h3>
<hr className="lineRow" style={{ }}></hr>
<Grid container spacing={3} direction="row" justifyContent="flex-start">
{scores.map((score, index) => {
if(score.gameDate === date && score.gameStatus === "scheduled" || score.gameStatus === "upcoming")
return (
<Scores
className="scroll-box-item"
role="listitem"
key={index}
id={index}
time={score.gameDateandTime}
gameStatus={score.gameStatus === "scheduled" ? "Upcoming" : ""}
homeTeam={score.homeTeam}
homePoints={score.homePoints}
awayPoints={score.awayPoints}
awayTeam={score.awayTeam}
/>
);
})}
</Grid>
</div>
);
}
export default NHL;
How can I access the gameId from the NHL function and use that in my Score component?

Formik on submit not called with Nextjs13

i created a form in nextjs13 using Formik, Material UI and Yup, but upon click the submit buttom the form get append to the url as queries and the onSubmit button is never called.
i already have use client at the top of my page, yet the validation and onsubmit is not working
below is my form, i cant realy figure out what am doing wrongly
<Formik
validationSchema={validationSchame}
initialValues={{
username: "",
password: "",
}}
onSubmit={async (values, formikHelpers) => {
console.log(values);
}}
>
{({ errors }) => {
return (
<Form>
<Grid item sx={{ marginBottom: 1 }}>
<Field
sx={{ width: "300px" }}
name="username"
as={StyledRedditTextField}
placeholder="Username"
label="Username"
size="medium"
/>
</Grid>
<Grid item>
<Field
sx={{ width: "300px", marginBottom: 2 }}
name="password"
as={StyledRedditTextField}
placeholder="Password"
label="Password"
size="medium"
type="password"
/>
</Grid>
<Grid item>
<Button
type="submit"
variant="contained"
color="primary"
sx={{ width: "300px" }}
size="large"
>
Sign In
</Button>
</Grid>
</Form>
);
}}
</Formik>

How to use different image on mobile in ReactJs Slick

Is there any way to use mobile image different from the desktop mode in react slick slider? I can use display none for breakpoints but what I want to learn, Is there any different way to do it?
const Hero = () => {
const classes = useStyle();
const { push } = useRouter();
const [sliderState, setSliderState] = useState(heroSliderData);
const [my_swiper, set_my_swiper] = useState({});
return (
<section className={classes.section}>
<Grid style={{ width:"100%", padding: "0px" }}>
<Swiper
loop={true}
navigation={true}
onInit={(ev) => {
set_my_swiper(ev);
}}
>
{sliderState.map(({ id, mainheading, mainheading2, subheading, subheading2, buttontext, image }) => (
<SwiperSlide key={id}>
<Grid item className={classes.hero}>
<img className={classes.heroimg} src={image} style={{ position:"relative"}} />
<Grid item xs={12} style={{ position:"absolute", top:"30%", left:"0", right:"0", textAlign: "center" }}>
<Typography variant="h1" className={classes.h1}>
{mainheading}<br />
{mainheading2}
</Typography>
</Grid>
<Grid item xs={12} style={{ position:"absolute", top:"42%", left:"0", right:"0", textAlign: "center" }}>
<Typography variant="h2" className={classes.h2}>
{subheading}
<br/>
{subheading2}
</Typography>
</Grid>
<Grid item xs={12} style={{ position:"absolute", top:"52%", left:"0", right:"0", textAlign: "center" }}>
<Button
variant="contained"
onClick={() => push("/teklif-al")}
className={classes.teklifal}
>
{buttontext}
</Button>
</Grid>
</Grid>
</SwiperSlide>
))}
</Swiper>
</Grid>
</section>
);
};
This is my code that I am working on it
Have you tried to use an IF clause to show and hide images?
See docs of React Slick.
import React, { Component } from "react";
import Slider from "react-slick";
export default class MultipleItems extends Component {
render() {
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3
};
return (
<div>
<h2> Multiple items </h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
<div>
<h3>9</h3>
</div>
</Slider>
</div>
);
}
}
And modify like this:
import React, { Component } from "react";
import Slider from "react-slick";
export default class MultipleItems extends Component {
const showOnMobile = document.innerWidth < 769;
render() {
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3
};
return (
<div>
<h2> Multiple items </h2>
<Slider {...settings}>
{showOnMobile &&
<div>
<h3>1</h3>
</div>
}
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
<div>
<h3>9</h3>
</div>
</Slider>
</div>
);
}
}

Bootstrap Form - Save Form Data Into an array

I have an array of football matches that I'll like users to enter their predictions. The issue I'm facing is that I'm unable to get save this form into an array.
Here is the visual look of the form.
Current form output
Here's my react code
import React, { useEffect, useState } from 'react';
import { Row, Col } from 'antd';
import moment from 'moment';
import { PredictTag, PotTitle, AmountInput } from '../../styles/styling';
import { Form, Container } from 'react-bootstrap';
import { produce } from "immer";
const StakeForm = (props) => {
const { potter } = props;
const [inputList, setInputList] = useState([
]);
const pots = potter.pot.findPot.pot;
useEffect(() => {
pots.slice(0, 4).map(() => {
setInputList(currentInput => [{
pot: {home_score: '', away_score: ''}
}
]);
})
},[]);
return (
<Container>
<Row justify="space-around" align="middle">
<Col span={12}><PotTitle>{potter.pot.findPot.pot_name}</PotTitle></Col>
<Col span={12} className="mt-2">
<PredictTag>Home</PredictTag>
<PredictTag>Away</PredictTag>
</Col>
</Row>
<Form>
{pots.map(({_id, home_team, away_team, date, time}) => (
<Row justify="space-around" align="middle" key={_id}>
<Col span={12}>
<h6>{home_team} vs {away_team}</h6>
<p>{moment(date).format("MMM Do, YYYY")} | {moment(time).format('LT')}</p>
</Col>
<Col span={12}>
{inputList.map((item, index) => (
<Container key={index}>
<Row>
<Col span={12}>
<Form.Group controlId="home" style={{ width: 100, }}>
<Form.Control as="select"
onChange={(e) => {
const home_score = e.target.value;
setInputList((currentInput) =>
produce(currentInput, (v) => {
v[index].pot.home_score = home_score;
})
)}}
>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</Form.Control>
</Form.Group>
</Col>
<Col span={12}>
<Form.Group controlId="away" style={{ width: 100, float: 'left' }}>
<Form.Control as="select"
onChange={(e) => {
const away_score = e.target.value;
setInputList((currentInput) =>
produce(currentInput, (v) => {
v[index].pot.away_score = away_score;
})
)}}
>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</Form.Control>
</Form.Group>
</Col>
</Row>
</Container>
))}
</Col>
</Row>
))}
<pre>{JSON.stringify(inputList, null, 2)}</pre>
</Form>
</Container>
);
};
export default StakeForm;
Currently, all home_score and away_score fields only return a single output rather than creating an object for each of the matches. Please do help me on this.

How to make Material-UI GridListTitleBar and Image a Link in ReactJS

I am using Material UI GridList to display a list of Events in React. Everything is working fine except that I am not able to make Title or Image a Link. Does anyone know how to make Title and Image a Link?
Here is my Component.
<div className={classes.root}>
<GridListTile key="Subheader" style={{ height: "auto" }}>
<ListSubheader component="div">This is List of Events</ListSubheader>
</GridListTile>
<GridList
cellHeight={330}
cols={matches ? 1 : 3}
className={classes.gridList}
spacing={12}
>
{tileData.length > 0 &&
tileData.map((tile, index) => {
return (
<GridListTile
key={Math.floor(Math.random() * new Date().getTime())}
>
<img src={tile.eventImage} alt={tile.title} />
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.description}</span>}
actionIcon={<IconButton title={tile.title} />}
/>
</GridListTile>
);
})}
</GridList>
</div>
);
Update
This is an update to the answer that was given below. The first image is now smaller than the rest of the images after update the code with the solution given below.
Here is the new code that I am trying:
<div className={classes.root}>
<GridListTile key="Subheader" style={{ height: "auto" }}>
<ListSubheader component="div">This is List of Events</ListSubheader>
</GridListTile>
<GridList
cellHeight={330}
cols={matches ? 1 : 3}
className={classes.gridList}
spacing={12}
>
{tileData.length > 0 &&
tileData.map((tile, index) => {
return (
<GridListTile
key={Math.floor(Math.random() * new Date().getTime())}
>
<a href={"events/" + tile._id + "/eventcomments"}>
<img
src={tile.eventImage}
alt={tile.title}
className="MuiGridListTile-imgFullHeight"
/>
<GridListTileBar title={tile.title} />
</a>
</GridListTile>
);
})}
</GridList>
</div>
Try wrapping the image with an anchor tag like this:
// ...
<GridListTile key={Math.floor(Math.random() * new Date().getTime())}>
<a href="https://www.google.com/">
<img src={tile.eventImage} alt={tile.title} className="MuiGridListTile-imgFullHeight" />
</a>
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.description}</span>}
actionIcon={<IconButton title={tile.title} />}
/>
</GridListTile>
// ...
It is important, after wrapping the image inside an anchor tag to add the class MuiGridListTile-imgFullHeight to the image to keep the same styling of the grid. Normally this class is added automatically, but if you wrap it inside an anchor tag it isn't. So you need to add it manually.
Update
The image shows expected behavior, because your first image is not wide enough to cover the whole tile and you only added the class to scale the img to full height. There is also a class to scale to full width: MuiGridListTile-imgFullWidth, but you can't use both of these classes together for your use case as the styles conflict (see the style definition here: https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/GridListTile/GridListTile.js).
You can try to set the width to 100% in the image style prop:
<img
// ...
style={{ width: "100%" }}
className="MuiGridListTile-imgFullHeight"
/>
I eventually managed to get it to work without breaking or stretching my images, and here is what I did.
<div className={classes.root}>
<GridListTile key="Subheader" style={{ height: "auto" }}>
<ListSubheader component="div">This is List of Events</ListSubheader>
</GridListTile>
<GridList
cellHeight={330}
cols={matches ? 1 : 3}
className={classes.gridList}
spacing={12}
>
{tileData.length > 0 &&
tileData.map((tile, index) => {
return (
<GridListTile
component={Link}
to={"/events/" + tile._id + "/eventcomments"}
key={Math.floor(Math.random() * new Date().getTime())}
>
<img src={tile.eventImage} alt={tile.title} />
<GridListTileBar title={tile.title} />
</GridListTile>
);
})}
</GridList>
</div>
const Gallery = () => {
const classes = useStyles();
return (
<Fragment>
<div style={{background: "black"}}>
<Toolbar/>
<Grid container spacing={0}>
<Grid item xs={12}>
<Paper className={classes.paper}>GALERIA</Paper>
<div className={classes.root}>
<GridList cellHeight={280} className={classes.gridList} cols={1}>
{tileData.map((tile) => (
<GridListTile style={{ width: "100%" }} key={tile.img} cols={tile.cols || 1}>
<img src={tile.img} alt={tile.title} />
</GridListTile>
))}
</GridList>
</div>
</Grid>
</Grid>
</div>
</Fragment>
)
}
export default Gallery;
You can change the type of underlying component rendered by the GridListTime Material-UI component. Just add the component="a" to have it render as an anchor tag. Then you may specify an href prop to pass in your route. See below:
<GridList cellHeight={160} className={classes.gridList} cols={3}>
{tileData.map((tile) => (
<GridListTile key={tile.img} cols={tile.cols || 1} component="a" href="/">
<img src={tile.img} alt={tile.title} />
</GridListTile>
))}
</GridList>

Resources