Why are all the dropdowns of cards happening at the same time? - reactjs

I am using Material UI in a React app.
I have implemented cards with expandable dropdowns; click a card, get more info.
I want to implement multiple cards, separately expandable. Currently when I click the down arrow (to expand) on one card all cards expand.
I can't figure out what's going wrong. Here is my code.
const ExpandMore = styled((props) => {
const { expand, ...other } = props;
return <IconButton {...other} />;
})(({ theme, expand }) => ({
transform: !expand ? 'rotate(0deg)' : 'rotate(180deg)',
marginLeft: 'auto',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest,
}),
}));
function Blogs(){
const [expanded, setExpanded] = React.useState(false);
const handleExpandClick = () => {
setExpanded(!expanded);
};
return (
<>
<Grid container direction="row" justifyContent="center">
<Grid item xs={4}>
<Box m={6}>
<Card sx={{ maxWidth: 345 }}>
<CardHeader
title="It’s a cocktail o’clock."
subheader="May 14, 2021"
/>
<CardMedia
component="img"
height="194"
image="https://img.freepik.com/free-photo/selection-various-cocktails-table_140725-2909.jpg?w=2000"
alt="Paella dish"
/>
<CardContent>
<Typography variant="body1" color="text.secondary">
Beat The Heat With Chilled Cocktails At The Best Bars In New York.
</Typography>
</CardContent>
<CardActions disableSpacing>
<ExpandMore
expand={expanded}
onClick={handleExpandClick}
aria-expanded={expanded}
aria-label="show more"
>
<ExpandMoreIcon />
</ExpandMore>
</CardActions>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<Typography paragraph>To a foodie, summer means one thing and one thing only – DRINKS!</Typography>
<Typography paragraph>
Yes people, we know it’s hot out there and the only way to quench your thirst is by guzzling down a bunch of ice-cold cocktails
</Typography>
<Typography paragraph>
<h4>1.The Bar Room at The Beekman</h4>
Visit the beautiful Bar Room in the historic Beekman Hotel for high-key romance that really wows.
Do try the whiskey sour.One of the best drinks available.
<h4>2.Dublin House</h4>
You can never go wrong with Sláinte! Margarita,Pot O'Gold, & Irish Old Fashioned
<h4>3.Russian Samovar</h4>
Alpensahne,Amarula Cream Liqueur, Caribou,Feni
</Typography>
</CardContent>
</Collapse>
</Card>
</Box>
</Grid>
<Grid item xs={4}>
<Box m={6}>
<Card sx={{ maxWidth: 345 }}>
<CardHeader
title="Winner Winner Pizza Dinner"
subheader="May 14, 2021"
/>
<CardMedia
component="img"
height="194"
image="https://cdn.shopify.com/s/files/1/0624/9853/articles/20220211142645-margherita-9920.jpg?crop=center&height=800&v=1660843558&width=800"
alt="Paella dish"
/>
<CardContent>
<Typography variant="body2" color="text.secondary">
Beat The Heat With Chilled Cocktails At The Best Bars In New York.
</Typography>
</CardContent>
<CardActions disableSpacing>
<ExpandMore
expand={expanded}
onClick={handleExpandClick}
aria-expanded={expanded}
aria-label="show more"
>
<ExpandMoreIcon />
</ExpandMore>
</CardActions>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<Typography paragraph>To a foodie, summer means one thing and one thing only – DRINKS!</Typography>
<Typography paragraph>
Yes people, we know it’s hot out there and the only way to quench your thirst is by guzzling down a bunch of ice-cold cocktails
</Typography>
<Typography paragraph>
<h4>1.The Bar Room at The Beekman</h4>
Visit the beautiful Bar Room in the historic Beekman Hotel for high-key romance that really wows.
Do try the whiskey sour.One of the best drinks available.
<h4>2.Dublin House</h4>
You can never go wrong with Sláinte! Margarita,Pot O'Gold, & Irish Old Fashioned
<h4>3.Russian Samovar</h4>
Alpensahne,Amarula Cream Liqueur, Caribou,Feni
</Typography>
</CardContent>
</Collapse>
</Card>
</Box>
</Grid>
</Grid>
</>
);
}

Related

material-ui horizontally align two cards below first card

How can I align Graph Two and Graph three horizontally below Graph One ?
In other words I want to leave Graph One card how it is but move Graph two so it is on the same level and Graph three and they are horizontally aligned with one another below Graph One
This is what I have so far
import React from "react";
import Grid from "#mui/material/Grid";
import Container from "#mui/material/Container";
import Box from "#mui/material/Box";
import Typography from "#mui/material/Typography";
import Card from "#mui/material/Card";
import CardActions from "#mui/material/CardActions";
import CardContent from "#mui/material/CardContent";
import Button from "#mui/material/Button";
import Paper from "#mui/material/Paper";
const styles = {
card: {
minWidth: 275,
display: "inline-block"
}
};
const YourCardOne = () => {
return (
<Card variant="outlined" style={{ height: "200%" }}>
<CardContent>
<Typography color="textSecondary" gutterBottom>
Graph One
</Typography>
<Typography variant="h5" component="h2">
Sarah Doria
</Typography>
<Typography color="textSecondary">Position</Typography>
<Typography variant="body2" component="p">
Company
<br />
{'"a benevolent smile"'}
</Typography>
</CardContent>
<CardActions></CardActions>
</Card>
);
};
const YourCardTwo = () => {
return (
<Card variant="outlined" style={{ height: "100%" }}>
<CardContent>
<Typography color="textSecondary" gutterBottom>
Graph Two
</Typography>
<Typography variant="h5" component="h2">
Sarah Doria
</Typography>
<Typography color="textSecondary">Position</Typography>
<Typography variant="body2" component="p">
Company
<br />
{'"a benevolent smile"'}
</Typography>
</CardContent>
<CardActions></CardActions>
</Card>
);
};
const YourCardThree = () => {
return (
<Card variant="outlined" style={{ height: "100%" }}>
<CardContent>
<Typography color="textSecondary" gutterBottom>
Graph Three
</Typography>
<Typography variant="h5" component="h2">
Sarah Doria
</Typography>
<Typography color="textSecondary">Position</Typography>
<Typography variant="body2" component="p">
Company
<br />
{'"a benevolent smile"'}
</Typography>
</CardContent>
<CardActions></CardActions>
</Card>
);
};
export default function GraphBackDrop() {
return (
<div>
<Container>
<Grid
container
spacing={3}
direction="row"
justify="center"
alignItems="stretch"
>
<Grid item xs={48}>
<Grid container spacing={25}>
<Grid item xs={12}>
<YourCardOne />
</Grid>
<Grid item xs={20} >
<YourCardTwo />
</Grid>
</Grid>
</Grid>
<Grid item xs={20}>
<YourCardThree />
</Grid>
</Grid>
</Container>
</div>
);
}
You can update your GraphBackDrop component to this:
export default function GraphBackDrop() {
return (
<Container>
<Grid
container
spacing={3}
justifyContent="center"
alignItems="stretch"
>
<Grid item xs={12}>
<YourCardOne />
</Grid>
<Grid item xs={12} sm={6}>
<YourCardTwo />
</Grid>
<Grid item xs={12} sm={6}>
<YourCardThree />
</Grid>
</Grid>
</Container>
);
}
Note: xs, sm, md, lg & xl are identified as breakpoints. It sets the number of columns the grid item uses. It can't be greater than the total number of columns of the container (12 by default).
If you want to learn more about MUI Grid component, refer to this official documentation.

Box component inserting text to 'start' and 'end'

I am using material UI components and I'm trying to make a card component. I want my text will be in the same row inbox component("phase" and "2" have to be in the same row). However, I couldn't do it. Here is my code;
<Card className={classes.rootMultiple} variant='outlined'>
<CardContent>
<Box>
<Box justifyContent={'start'}>
<Typography
variant='h5'
component='h2'
className={classes.titleMultiple}
>
phase
</Typography>
</Box>
<Box display='flex' justifyContent={'end'}>
<Typography
variant='h7'
component='h2'
className={classes.descriptionMultiple}
>
2
</Typography>
</Box>
</Box>
</CardContent>
</Card>;
Try to specify the display and flexDirection attributes in the parent's Box.
Then use the flex attribute on the children's `Box:
<Card className={classes.rootMultiple} variant='outlined'>
<CardContent>
<Box sx={{
display: 'flex',
flexDirection: 'row',
}}>
<Box flex={1}>
<Typography
variant='h5'
component='h2'
className={classes.titleMultiple}
>
phase
</Typography>
</Box>
<Box flex={0}>
<Typography
variant='h7'
component='h2'
className={classes.descriptionMultiple}
>
2
</Typography>
</Box>
</Box>
</CardContent>
</Card>
You can just write a Grid (that uses flex) with justify-content: space-between.
<Card className={classes.rootMultiple} variant='outlined'>
<CardContent>
<Grid container justifyContent="space-between">
<Grid item>
<Typography
variant='h5'
component='h2'
className={classes.titleMultiple}
>
phase
</Typography>
</Grid>
<Grid item>
<Typography
variant='h7'
component='h2'
className={classes.descriptionMultiple}
>
2
</Typography>
</Grid>
</Grid>
</CardContent>
</Card>
No need to make other components; less is better. Of course you can use Box with flex style, but Grid does it for you.
Note that h7 isn't a valid value for variant inside Typography.
EDIT: I wrote space-between only because your example prints the texts in the margins, but of corse you can use what you want: they will be always in same row.

How to properly set the background of Container or other MUI Components?

Hi I'm migrating my code to MUI components and I'm having quite the difficulty to style it, I haven't fine any references for Container MUI component for example but I have found for Box, Cards, Paper, etc etc... and I wanted to know how to do it for the Container
This is my attempt of styling lol
and this is what I wanna achieve (I did my best to edit that lol)
My code, I do not know if I'm "boxing" things correctly but I think I do in this particular case, also I'm using pl to add some padding to the left because wasn't able to center it properly neither but that at least fixed the issue temporally. (I did try alignitems and all that stuff but it just ignores it)
<Container fixed bgcolor = "#f2f6fc" >
<Box bgcolor = "#f2f6fc" mb={2} pt={2} sx={{textAlign:'center'}}>
<Button
startIcon = {<HouseSharpIcon />}
variant = "contained"
color = "secondary"
size = "medium"
onClick={goHome} >
Regresar
</Button>
</Box>
<Box bgcolor = "#f2f6fc" pl={45} sx={{textAlign:'left', width: "500px"}}>
<Card >
<CardContent>
<Typography variant = "h5" gutterBottom>
Listado de libros por estudiante
</Typography>
<Typography variant="h6" component="div">
Acudiente: {user.displayName}
</Typography>
<Typography variant="h6" component="div">
Estudiante: {nombre}
</Typography>
<Typography variant="h6" component="div">
Datos del estudiante:
</Typography>
<Typography >
Colegio: {colegio}
<br />
Grado: {grado}
</Typography>
</CardContent>
</Card>
</Box>
<Box bgcolor = "#f2f6fc" pt={2} mb={2} pl={30} sx={{height: '650px', width: "780px", textAlign:'center'}}>
<DataGrid
rows={librosNuevos}
columns={columns}
pageSize={20}
rowsPerPageOptions={[20]}
checkboxSelection
//Store Data from the row in another variable
onSelectionModelChange = {(id) => {
setSelectionModel(id);
const selectedIDs = new Set(id);
const selectedRowData = librosNuevos.filter((row) =>
selectedIDs.has(row.id)
);
setLibrosID1(selectedRowData)
}
}
{...librosNuevos}
/>
</Box>
</Container>
I hope you already found the answer, but still if someone is looking for this here's what I use :
<Container style={{ background: '#f2f6fc' }} >

Why isn't the image rendering in Material-UI's CardMedia?

I'm trying to fit an image in CardMedia. Here's the code:
<Card className={classes.root}>
<CardActionArea>
<CardMedia
className={classes.media}
image="../public/assets/bnha.jpg"
/>
<CardContent>
<Typography className={classes.title}>
Vigilante: Boku no Hero Academia Illegals Chapter 97
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Mar 13, 2021
</Typography>
</CardContent>
</CardActionArea>
</Card>
I can't figure out why the image won't render. Any idea what the issue is?

How to dynamically create button for calling specific action using map array in react

I tried to map an array in react and tried to generate a button that will perform a specific action ,that is referencing another object generated by the same array using map() function.I'm using material-ui to speed up my development process.
I am very new to react (actually this is my first project with react), so maybe this is just simple question to implement 'state' in react, but i'm a little bit confusing to use this and bind syntax properly.
P.S -So excuse me for my stupidity :>
Follow this link to reproduce the code
and this is the code i got trouble with:
const products = [
{
id: 1,
img: "https://image.flaticon.com/icons/png/512/676/676434.png",
title: "Pineaple",
price: "Rp. 14.000",
desc: "Pineaple is one of nutritious food"
},
{
id: 2,
img: "https://image.flaticon.com/icons/png/512/676/676433.png",
title: "Banana",
price: "Rp. 14.000",
desc: "Banana is one of nutritious food"
},
{
id: 3,
img: "https://image.flaticon.com/icons/png/512/676/676441.png",
title: "Dragonfruit",
price: "Rp. 14.000",
desc: "Dragonfruit is one of nutritious food"
},
];
export default function Posts(props) {
const [open, setOpen] = React.useState(false);
function handleClickOpen() {
setOpen(true);
}
function handleClose() {
setOpen(false);
}
return (
<div>
<Grid container spacing={1} justify="center">
{products.map(product => (
<Grid item xs={6} sm={3} md={2} key={product.id}>
<Card>
<CardActionArea>
<CardMedia
component="img"
width="auto"
height="auto"
image={product.img}
/>
<CardContent>
<Typography component="h2"> {product.title} </Typography>
<Typography variant="body2" color="primary" component="p">
{" "}{product.price}{" "}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button onClick={handleClickOpen}>
Buy
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
{products.map(product => (
<Dialog
key={product.id}
fullScreen
open={open}
onClose={handleClose}
>
<AppBar position="sticky">
<Toolbar>
<IconButton onClick={handleClose}>
<CloseIcon />
</IconButton>
<Typography> {product.title} </Typography>
<Button onClick={handleClose}> buy </Button>
</Toolbar>
</AppBar>
<List className={classes.dialogue}>
<img src={product.img} alt={product.title} />
<ListItem button>
<ListItemText primary={product.title} secondary={product.desc}/>
</ListItem>
</List>
</Dialog>
))}
</div>
);
}
I want to make onclick button generated by mapped array to reference to specific action (show specific dialog within array list). I also want to implement same method for onSubmit on 'buy' button in the Dialog.
Screenshoot: https://imgur.com/a/M4v5LOu
(I click buy on 'pineaple' but react render all list and show the latest object in a the list which is 'dragonfruit'.)
I guess i'll use redux but maybe not right now.
Anyway that's it, I really appreciate any response and helps :)
Thanks!
There are several ways you can solve this but I will show you one. You are making use of React Hooks and you have a hook for setting the open/close state. In my solution, I make slight modification by adding another hook to set the selected product and then checking if both open and the product are set.
export default function Posts(props) {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const [product, setProduct] = React.useState(null);
function handleClickOpen(event, item) {
event.persist();
setProduct(item);
setOpen(true);
}
function handleClose() {
setOpen(false);
}
return (
<div style={{ margin: 0, padding: 0 }}>
<Grid container spacing={1} justify="center">
{products.map(product => (
<Grid item xs={6} sm={3} md={2} key={product.id}>
<Card elevation={0}>
<CardActionArea>
<CardMedia
component="img"
width="auto"
height="auto"
image={product.img}
/>
<CardContent>
<Typography component="h2"> {product.title} </Typography>
<Typography variant="body2" color="primary" component="p">
{' '}
{product.price}{' '}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button
variant={'outlined'}
size="small"
color="primary"
onClick={event => handleClickOpen(event, product)}
>
Buy
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
{open && product && (
<Dialog
key={product.id}
className={classes.dialogue}
fullScreen
open={open}
onClose={handleClose}
BackdropProps={{ classes: { root: classes.root } }}
PaperProps={{ classes: { root: classes.paper } }}
>
<AppBar position="sticky">
<Toolbar>
<IconButton
edge="start"
color="inherit"
onClick={handleClose}
aria-label="Close"
>
<CloseIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
{product.title}
</Typography>
<Button color="inherit" onClick={handleClose}>
buy
</Button>
</Toolbar>
</AppBar>
<List className={classes.dialogue}>
<Image
className={classes.images}
src={product.img}
alt={product.title}
/>
<ListItem button>
<ListItemText primary={product.title} secondary={product.desc} />
</ListItem>
</List>
</Dialog>
)}
</div>
);
}
In your code, you didn't have a way to track the currently selected product hence you always get the last item in the loop. By using another hook for the selected product, I can track the selected product. I hope this helps you and good luck in your mastery of React.
You are having two states open and close.
You are using map on array and showing the dialog box.
The dialog box will open when open state is true.
This will be true for all elements in the array. Dialog box will be shown for all elements.
Now, they will overlap on each other and you can only see the last one.
When you click on close dialog your open state set to false and all the dialogs are closed.
Hint :-
Maintain a state that will contain the id of element for which dialog is to be shown. Show dialog only when id state matches with the element's id

Resources