Why come card content is not showing in MUI - reactjs

import React from "react";
import {
Card,
CardActions,
CardContent,
Button,
CardMedia,
Typography,
} from "#mui/material";
import ThumbUpAlt from "#mui/icons-material/ThumbUpAlt";
import Delete from "#mui/icons-material/Delete";
import MoreHoriz from "#mui/icons-material/MoreHoriz";
import moment from "moment";
import useStyles from "./styles";
const Post = ({ post }) => {
const classes = useStyles();
return (
<Card className={classes.card}>
<CardMedia
className={classes.media}
image={post.selectedFile}
title={post.title}
>
<div className={classes.overlay}>
<Typography variant="h6">{post.creator}</Typography>
<Typography variant="body2">
{moment(post.createdAt).fromNow()}
</Typography>
</div>
// till here the card is showing
<div className={classes.overlay2}>
<Button style={{ color: "white" }} size="small" onClick={() => {}}>
<MoreHoriz fontSize="default" />
</Button>
</div>
<div className={classes.details}>
<Typography variant="body2" color="textSecondary">
{post.tags.map((tag) => `#${tag}`)}
</Typography>
</div>
<CardContent>
<Typography className={classes.title} variant="h5" gutterBottom>
{post.message}
</Typography>
</CardContent>
<CardActions className={classes.cardActions}>
<Button size="small" color="primary" onClick={() => {}}>
<ThumbUpAlt fontSize="small" />
Like
{post.likeCount}
</Button>
<Button size="small" color="primary" onClick={() => {}}>
<Delete fontSize="small" />
Delete
</Button>
</CardActions>
</CardMedia>
</Card>
);
};
export default Post;
I'm passing data from parent to child as a prop.After this i'm mapping the prop in card.But the issue is card is only showing till classes.overlay afterwards nothing is showing.Also code is not showing in inspect.I don't know what the issue is as i'm new to MUI.
May i know what the issue is so that i can fix it

Is because you are wrapping your component inside the CardMedia tags, when it should be a self-closing tag, so your code should look like this:
const Post = ({ post }) => {
const classes = useStyles();
return (
<Card className={classes.card}>
<CardMedia
className={classes.media}
image={post.selectedFile}
title={post.title}
/> // <--- This is the change
<div className={classes.overlay}>
<Typography variant="h6">{post.creator}</Typography>
<Typography variant="body2">
{moment(post.createdAt).fromNow()}
</Typography>
</div>
<div className={classes.overlay2}>
<Button style={{ color: "white" }} size="small" onClick={() => {}}>
<MoreHoriz fontSize="default" />
</Button>
</div>
<div className={classes.details}>
<Typography variant="body2" color="textSecondary">
{post.tags.map((tag) => `#${tag}`)}
</Typography>
</div>
<CardContent>
<Typography className={classes.title} variant="h5" gutterBottom>
{post.message}
</Typography>
</CardContent>
<CardActions className={classes.cardActions}>
<Button size="small" color="primary" onClick={() => {}}>
<ThumbUpAlt fontSize="small" />
Like
{post.likeCount}
</Button>
<Button size="small" color="primary" onClick={() => {}}>
<Delete fontSize="small" />
Delete
</Button>
</CardActions>
</Card>
);
};
export default Post;

Related

When I click the Recipe button both recipes show at one time and not individually

I am trying to show 2 different recipes depending on what recipe button I am clicking and unsure how to get that to stop and only show individual recipes.
\\First Card
<Card style={{ width: '18rem' }} className="Chicken">
<Card.Img variant="top" src={chicken} className="Fav_image" />
<Card.Body>
<Card.Title className="Fav_title">Chicken Paprakash</Card.Title>
<Card.Text className="Fav_text">
This is one of my favourite fall/winter recipes to make.
</Card.Text>
<Button variant="outlined" onClick={handleOpen} className="button">Recipe</Button>
</Card.Body> <Card>
\\Second Card
<Card style={{ width: '18rem' }} className="Fajita">
<Card.Img variant="top" src={fajita} className="Fav_image" />
<Card.Body>
<Card.Title className="Fav_title">Chicken Fajitas</Card.Title>
<Card.Text className="Fav_text">
Great for when you only have a few minutes to cook dinner.
</Card.Text>
<Button variant="outlined" onClick={handleOpen} className="button">Recipe</Button>
</Card.Body> <Card>
Here is the issue:
I tried multiple different fixes on Stack overflow but not luck
I assume that you're using the same useState for onClick={handleOpen} in your button? They're both opening due to the shared useState. The best way to solve this is to make another component where you render the <Card/>. This way each card component regulates its own state.
First step will be to create a state to store current opened food item:
const [currentOpen, setCurrentOpen] = React.useState(false);
Also change item handle open and handle close
const handleOpen = (item) => {
setOpen(true);
setCurrentOpen(item);
};
const handleClose = (item) => {
setOpen(false);
setCurrentOpen(item);
};
Now simply check for current item open while returning a card:
{currentOpen === "chicken1" && ()
{currentOpen === "chicken2" && ()
Here is whole code (components/Favourites/index.jsx):
import React from "react";
import Card from "react-bootstrap/Card";
import board from "../../assets/Favourites/0.jpg";
import chicken from "../../assets/Favourites/1.jpg";
import fajita from "../../assets/Favourites/2.jpg";
import Backdrop from "#mui/material/Backdrop";
import Box from "#mui/material/Box";
import Modal from "#mui/material/Modal";
import Fade from "#mui/material/Fade";
import Button from "react-bootstrap/Button";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import Typography from "#mui/material/Typography";
// import Nav from 'react-bootstrap/Nav';
const style = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
border: "2px solid #000",
boxShadow: 24,
p: 4,
};
function Favourite() {
const [open, setOpen] = React.useState(false);
const [currentOpen, setCurrentOpen] = React.useState(false);
const handleOpen = (item) => {
setOpen(true);
setCurrentOpen(item);
};
const handleClose = (item) => {
setOpen(false);
setCurrentOpen(item);
};
return (
<>
<img
className="head-img"
src={board}
style={{ width: "100vw", height: "100vh" }}
alt="cutting board"
/>
<h1 className="Haleys_Favourites">Haley's Favourite Recipes</h1>
<Card style={{ width: "18rem" }} className="Chicken">
<Card.Img variant="top" src={chicken} className="Fav_image" />
<Card.Body>
<Card.Title className="Fav_title">Chicken Paprakash</Card.Title>
<Card.Text className="Fav_text">
This is one of my favourite fall/winter recipes to make.
</Card.Text>
<div>
<Button
variant="outlined"
onClick={() => handleOpen("chicken1")}
className="button"
>
Recipe
</Button>
{currentOpen === "chicken1" && (
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={open}
onClose={() => handleClose("chicken1")}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<Box sx={style}>
<Typography
id="transition-modal-title"
variant="h6"
component="h2"
className="chicken_title"
>
Chicken Paprakash
</Typography>
<Typography
id="transition-modal-title"
variant="subtitle1"
component="h2"
className="chicken_serving"
>
Serving: 4 people
</Typography>
<Row xs={1} md={2}>
<Col>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
>
Ingredients:
<ol>
<li>4 chicken legs</li>
<li>oil</li>
<li>half an onion (chopped) </li>
<li>4 tablespoons of paprika</li>
<li>2 1/2 cups chicken broth</li>
<li>1 tub of sour cream</li>
<li>1 tablespoon of flour</li>
<li>salt</li>
<li>egg noodles</li>
</ol>
</Typography>
</Col>
<Col>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
>
Instructions:
<ol>
<li>
Season chicken with salt and pepper then brown
chicken in oil.
</li>
<li>
As chicken is browning, combine sour cream and
flour.
</li>
<li>Put browned chicken in dutch oven.</li>
<li>Add more oil and cook onions until soft.</li>
<li>
Add paprika and stir completely. Add sour cream
and onion mix and stir completley and then add
chicken broth
</li>
<li>
Stir until all combined and cook for 10 minutes.
</li>
<li>
Pour sauce into dutch oven and cook at 350% for 45
minutes
</li>
<li>Serve with buttery egg noodles</li>
</ol>
</Typography>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
className="exit"
variant="subtitle1"
>
Click outside of the box to exit!
</Typography>
</Col>
</Row>
</Box>
</Fade>
</Modal>
)}
</div>
</Card.Body>
</Card>
<Card style={{ width: "18rem" }} className="Fajita">
<Card.Img variant="top" src={fajita} className="Fav_image" />
<Card.Body>
<Card.Title className="Fav_title">Chicken Fajitas</Card.Title>
<Card.Text className="Fav_text">
Great for when you only have a few minutes to cook dinner.
</Card.Text>
<div>
<Button
variant="outlined"
onClick={() => handleOpen("chicken2")}
className="button"
>
Recipe
</Button>
{currentOpen === "chicken2" && (
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={open}
onClose={() => handleClose("chicken2")}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<Box sx={style}>
<Typography
id="transition-modal-title"
variant="h6"
component="h2"
className="Fav_title"
>
Chicken Fajitas
</Typography>
<Typography
id="transition-modal-titles"
variant="subtitle1"
component="h2"
className="Fav_serving"
>
Serving: 4 people
</Typography>
<Row>
<Col md={6}>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
>
Ingredients:
<ol>
<li>3 chicken breast</li>
<li>oil</li>
<li>half an onion (sliced)</li>
<li>2 large peppers (sliced)</li>
<li>1-2 Old El Paso Fajita seasoning packets</li>
<li>Tortillas</li>
</ol>
</Typography>
</Col>
<Col md={6}>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
>
Instructions:
<ol>
<li>Cook chicken in oil until cooked.</li>
<li>Add packets of seasoning.</li>
<li>Add onion and peppers.</li>
<li>
1/4-2/3 cups (depending how many packets used).
</li>
<li>Cook everything for 3-5 minutes</li>
<li>
Put in tortilla with all condaments you want.
</li>
</ol>
</Typography>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
className="exit"
variant="subtitle1"
>
Click outside of the box to exit!
</Typography>
</Col>
</Row>
</Box>
</Fade>
</Modal>
)}
</div>
</Card.Body>
</Card>
{/* <Nav className="Fav_Home">
<Nav.Item>
<Nav.Link className="nav_home" href="/Home">Home</Nav.Link>
</Nav.Item>
</Nav> */}
</>
);
}
export default Favourite;

Display the correct CardContent in it's DialogContent

I'm trying intergrate an option to display the data of a Card it's Dialog, with there being multiple Cards.
Right now I'm getting all the data from Firebase and each record is being displayed in a Card. The problem is that the Dialog will only display the data of the last looped item in the map, not of the Card that I'm trying to display in the Dialog.
How can I get the corresponding data from a Card and put it in it's Dialog? E.g: I open the Dialog of the 4th Card and only the data of the 4th Card gets displayed
The code:
useEffect(() => {
const getEvents = async () => {
const data = await getDocs(eventsRef);
data.forEach((doc) => {
setEventList(data.docs.map((doc) => ({...doc.data(), id: doc.id})));
})
};
getEvents();
}, [])
return (
<>
<div className="stepper-title" style={{textAlign: "center"}}>
<b><h1>Aankomende afspraken</h1></b><br></br><p>Prik een afspraak die jou intereseerd</p>
</div>
<div className="event-list-container">
{
eventList && eventList.map((item, index) => {
return (
<div key={item.id}>
<Card variant="outlined" sx={{ width: 250 }}>
<CardContent>
<Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
{item.date}
</Typography>
<Typography variant="h5" component="div">
{item.occasion.title}
</Typography>
<Typography sx={{ mb: 1.5 }} color="text.secondary">
{item.location}
</Typography>
<Typography variant="body2">
{item.occasion.description}
</Typography>
</CardContent>
<CardActions>
card {index}
<Button onClick={handleClickOpen} size="small" itemID={item.id}>bekijken</Button>
<Dialog open={open} onClose={handleClose} PaperProps={{elevation: 1}} hideBackdrop>
<DialogContent>
<TextField
label="Titel"
defaultValue={eventList[index].occasion.title}
fullWidth
variant="standard"
/>
<TextField
label="Description"
defaultValue={eventList[index].occasion.description}
fullWidth
variant="standard"
/>
<TextField
label="Datum"
defaultValue={eventList[index].date}
fullWidth
variant="standard"
/>
<TextField
label="Locatie"
defaultValue={eventList[index].location}
fullWidth
variant="standard"
/>
<TextField
label="Naam"
defaultValue={eventList[index].organizer.name}
fullWidth
variant="standard"
/>
<TextField
label="E-mailadres"
defaultValue={eventList[index].organizer.email}
fullWidth
variant="standard"
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>terug</Button>
<Button onClick={handleClose}>Aanpassen</Button>
</DialogActions>
</Dialog>
</CardActions>
</Card>
</div>
)
})
}
</div>
</>
);

Uncaught TypeError: Cannot read properties of undefined (reading 'source') react v16

I'm trying to access data from commerceJS API fetched on a different module and passed down as a prop, the code only breaks when I call a nested product object with this error Uncaught TypeError: Cannot read properties of undefined (reading 'source').
Here is my code
//Product.jsx
import React from 'react';
import { Card, CardMedia, CardContent, CardActions, Typography, IconButton } from '#material-ui/core';
import { AddShoppingCart } from '#material-ui/icons';
import useStyles from './styles';
const Product = ({ product, onAddToCart }) => {
const classes = useStyles();
const handleAddToCart = () => onAddToCart(product.id, 1);
return (
<Card className={classes.root}>
<CardMedia
className={classes.media}
image={product.media.source}
component="img"
title={product.name}
/>
<CardContent>
<div className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
{product.name}
</Typography>
<Typography gutterBottom variant="h5" component="h2">
${product.price.formatted}
</Typography>
</div>
<Typography
dangerouslySetInnerHTML={{ __html: product.description }}
variant="body2"
color="textSecondary"
component="p"
/>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to Cart" onClick={handleAddToCart}>
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
);
};
export default Product;
import React from 'react';
import { Card, CardMedia, CardContent, CardActions, Typography, IconButton } from '#material-ui/core';
import { AddShoppingCart } from '#material-ui/icons';
import useStyles from './styles';
const Product = ({ product, onAddToCart }) => {
const classes = useStyles();
const handleAddToCart = () => onAddToCart(product.id, 1);
return (
<Card className={classes.root}>
<CardMedia
className={classes.media}
image={product.media.source}
component="img"
title={product.name}
/>
<CardContent>
<div className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
{product?.name}
</Typography>
<Typography gutterBottom variant="h5" component="h2">
${product?.price?.formatted}
</Typography>
</div>
<Typography
dangerouslySetInnerHTML={{ __html: product.description }}
variant="body2"
color="textSecondary"
component="p"
/>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to Cart" onClick={handleAddToCart}>
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
);
};
export default Product;
try this code:
import React from 'react';
import { Card, CardMedia, CardContent, CardActions, Typography, IconButton } from '#material-ui/core';
import { AddShoppingCart } from '#material-ui/icons';
import useStyles from './styles';
const Product = ({ product, onAddToCart }) => {
const classes = useStyles();
const handleAddToCart = () => onAddToCart(product.id, 1);
return (
<Card className={classes.root}>
<CardMedia
className={classes.media}
image={product?.media?.source}
component="img"
title={product?.name}
/>
<CardContent>
<div className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
{product?.name}
</Typography>
<Typography gutterBottom variant="h5" component="h2">
${product?.price?.formatted}
</Typography>
</div>
<Typography
dangerouslySetInnerHTML={{ __html: product?.description }}
variant="body2"
color="textSecondary"
component="p"
/>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to Cart" onClick={handleAddToCart}>
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
);
};
export default Product;
It'll display the image if I delete the className property and access to my object key
Code here:
<CardMedia
className={classes.media}
image={product.image.url}
component="img"
title={product?.name}
/>

With this code I get this error "onAddToCart is not a function" How can I fix it?

import React from "react";
import { CardMedia, Card, CardContent, CardActions, Typography, IconButton } from "#mui/material";
import { AddShoppingCart } from "#mui/icons-material";
import useStyles from "./styles"
const Product = ({ product, onAddToCart }) =>{
const classes = useStyles();
return(
<Card className={classes.root}>
<CardMedia className={classes.media} image={product.image.url} title={product.name}/>
<CardContent>
<div className={classes.cardContent}>
<Typography variant="h5" gutterBottom >
{product.name}
</Typography>
<Typography variant="h5" >
{product.price.formatted_with_symbol}
</Typography>
</div>
<Typography dangerouslySetInnerHTML= {{ __html: product.description }} variant="body2" color="textSecondary"/>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to card" onClick={() => onAddToCart(product.id, 1)}>
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
)
}
export default Product;
You need to look at how the prop onAddToCart is transferred to the component Product
Search something like: <Product ... />

How to put different content for each cards

I am using material ui album template for my react app
I want to put different image and different text for each cards for this when I remove this array it create the problems in responsiveness of the cards
I tried to put separte grid for each cards but thats some how solve the issue but that responsiveness of the template does not remain same
here is my demo code
https://codesandbox.io/s/material-demo-pz8df
Make sure you're updating the right cards array. Use an array of objects as well, where each object has a key for an image-link and one for the description. In the .map() we'll use these values to render the content. Here's a working sandbox: https://codesandbox.io/s/material-demo-3v44c
The responsiveness will work like expected.
Working code:
import React from "react";
import AppBar from "#material-ui/core/AppBar";
import Button from "#material-ui/core/Button";
import CameraIcon from "#material-ui/icons/PhotoCamera";
import Card from "#material-ui/core/Card";
import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import CardMedia from "#material-ui/core/CardMedia";
import CssBaseline from "#material-ui/core/CssBaseline";
import Grid from "#material-ui/core/Grid";
import Toolbar from "#material-ui/core/Toolbar";
import Typography from "#material-ui/core/Typography";
import { makeStyles } from "#material-ui/core/styles";
import Container from "#material-ui/core/Container";
import Link from "#material-ui/core/Link";
function MadeWithLove() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{"Built with love by the "}
<Link color="inherit" href="https://material-ui.com/">
Material-UI
</Link>
{" team."}
</Typography>
);
}
const useStyles = makeStyles(theme => ({
icon: {
marginRight: theme.spacing(2)
},
heroContent: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(8, 0, 6)
},
heroButtons: {
marginTop: theme.spacing(4)
},
cardGrid: {
paddingTop: theme.spacing(8),
paddingBottom: theme.spacing(8)
},
card: {
height: "100%",
display: "flex",
flexDirection: "column"
},
cardMedia: {
paddingTop: "56.25%" // 16:9
},
cardContent: {
flexGrow: 1
},
footer: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(6)
}
}));
const cards = [
{
img:
"https://images.unsplash.com/photo-1564135624576-c5c88640f235?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=3300&q=80",
desc: "Campsite"
},
{
img:
"https://images.unsplash.com/photo-1564198879220-63f2734f7cec?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2072&q=80",
desc: "Space"
}
];
export default function Album() {
const classes = useStyles();
return (
<React.Fragment>
<CssBaseline />
<AppBar position="relative">
<Toolbar>
<CameraIcon className={classes.icon} />
<Typography variant="h6" color="inherit" noWrap>
Album layout
</Typography>
</Toolbar>
</AppBar>
<main>
{/* Hero unit */}
<div className={classes.heroContent}>
<Container maxWidth="sm">
<Typography
component="h1"
variant="h2"
align="center"
color="textPrimary"
gutterBottom
>
Album layout
</Typography>
<Typography
variant="h5"
align="center"
color="textSecondary"
paragraph
>
Something short and leading about the collection below—its
contents, the creator, etc. Make it short and sweet, but not too
short so folks don&apos;t simply skip over it entirely.
</Typography>
<div className={classes.heroButtons}>
<Grid container spacing={2} justify="center">
<Grid item>
<Button variant="contained" color="primary">
Main call to action
</Button>
</Grid>
<Grid item>
<Button variant="outlined" color="primary">
Secondary action
</Button>
</Grid>
</Grid>
</div>
</Container>
</div>
<Container className={classes.cardGrid} maxWidth="md">
{/* End hero unit */}
<Grid container spacing={4}>
{cards.map(card => (
<Grid item key={card} xs={12} sm={6} md={4}>
<Card className={classes.card}>
<CardMedia
className={classes.cardMedia}
image={card.img}
title="Image title"
/>
<CardContent className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
Heading
</Typography>
<Typography>{card.desc}</Typography>
</CardContent>
<CardActions>
<Button size="small" color="primary">
View
</Button>
<Button size="small" color="primary">
Edit
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
</main>
{/* Footer */}
<footer className={classes.footer}>
<Typography variant="h6" align="center" gutterBottom>
Footer
</Typography>
<Typography
variant="subtitle1"
align="center"
color="textSecondary"
component="p"
>
Something here to give the footer a purpose!
</Typography>
<MadeWithLove />
</footer>
{/* End footer */}
</React.Fragment>
);
}

Resources