I am trying to make a card grid where the user can expand the card to view its details. The issue I am facing with the react hooks is that the function is getting called for all cards instead of the particular card I am clicking the button. As a result, all the cards are getting expanded.
Here's my code for reference.
Any help is highly appreciated. Thank you!
function Album(props) {
return (
<div>
<Card className={classes.card}>
<Card.Text >
<p className={classes.heading}>
{props.blogTitle}
</p>
</Card.Text>
<Card.Body>
<Card.Img
src={props.imgsrc}
alt="Card image"
className={classes.cardMedia}
/>
{props.cardOpen &&
<AnimatePresence>
<motion.div
initial={{opacity:0}}
animate={{opacity:1, transition:0.3}}
>
<p className={classes.desc} gutterbottom>
{props.blogDescription}
</p>
<div href={props.blogLink}
style={{color:"gray", fontSize:17, fontFamily:"calibri", fontSmooth: "auto", cursor:"pointer", display:"flex", justifyContent:"center"}}>
<LocalLibraryIcon style={{marginRight:7}}/>Read blog
</div>
</motion.div>
</AnimatePresence>
}
{(props.cardOpen) ?
<div onClick={props.isOpen} style={{float:"right", cursor:"pointer"}}>
<ExpandLessIcon style={{fontSize:40, marginTop:10, color:" #909090"}}/>
</div> : (
<div onClick={props.isOpen} style={{float:"right", cursor:"pointer"}}>
<ExpandMoreIcon style={{fontSize:40, marginTop:10, color:" #909090"}}/>
</div>
)}
</Card.Body>
</Card>
</div>
);
}
export default function ProjectItems() {
const [cardOpen, setCardOpen]= useState(false);
return (
<React.Fragment>
<CssBaseline />
<main>
<div className={classes.heroContent}>
<Container maxWidth="md">
<Typography
variant="h2"
align="center"
color="textPrimary"
className={classes.root}
gutterBottom
>
Blogs
</Typography>
</Container>
</div>
<Container maxWidth="md">
<Grid container spacing={4}>
{blogData.map(post => (
<Grid item xs={12} sm={6} md={4} key={post.id}>
<div>
<Album
blogId={post.id}
blogTitle={post.title}
blogDescription={post.summary}
imgsrc={post.image_link}
blogLink={post.article_link}
isOpen={()=>{
setCardOpen(!cardOpen);
}}
cardOpen={cardOpen}
/>
</div>
</Grid>
))}
</Grid>
</Container>
</main>
</React.Fragment>
);
}
Related
Hello I am trying to make a drag and drop in my application but I have got a huge error. I have no idea if property is missing because in IDE it is an error free code.
Uncaught Error: Could not find "store" in the context of "Connect(Droppable)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(Droppable) in connect options.
Down here are my components
3 Columns ( I want drag and drop across one column each, not between them)
const DetailColumns: React.FC<funcProps> = (props) => {
const onDragEnd = () => {};
return (
<Box
h="80vh"
borderWidth="0.5rem"
borderColor="orange.300"
borderRadius="1rem"
w="80%"
marginTop="2rem"
>
<Grid w="100%" h="100%" templateColumns="60% 20% 20%">
<Box border="0.5rem" borderColor="orange.300">
<RecipeDescriptionBox recipe={props.recipe} />
</Box>
<Box borderLeftWidth="0.5rem" borderColor="orange.300">
<RecipeStepsBox recipe={props.recipe} />
</Box>
<DragDropContext onDragEnd={onDragEnd}>
<Box borderLeftWidth="0.5rem" borderColor="orange.300">
<RecipeIngredientsBox recipe={props.recipe} />
</Box>
</DragDropContext>
</Grid>
</Box>
);
};
List of Items
<Box>
<ColumnHeader title="Steps" />
<Droppable droppableId="unique">
{(provided) => (
<Box {...provided.droppableProps} innerRef={provided.innerRef}>
{steps.map((step, index) => (
<DetailListItem
key={step}
itemName={step}
indexOfItem={index}
id={Math.random().toString()}
/>
))}
{provided.placeholder}
</Box>
)}
</Droppable>
</Box>
Item element
<Draggable draggableId={props.id} index={props.indexOfItem}>
{(provided) => (
<Box
{...provided.draggableProps}
{...provided.dragHandleProps}
innerRef={provided.innerRef}
>
<Flex margin="1rem">
<Box
bgGradient="linear(to-r, orange.200, orange.400)"
height="6vh"
width="6vh"
boxShadow="md"
rounded="md"
>
<Grid w="100%" h="100%" placeItems="center">
<Text color="white" fontWeight="700" fontSize="140%">
{props.amount && props.amount + props.unit}
{!props.amount && props.indexOfItem}
</Text>
</Grid>
</Box>
<Grid placeItems="center">
<Text marginLeft="1rem" fontWeight="500" fontSize="1.8rem">
{props.itemName}
</Text>
</Grid>
</Flex>
</Box>
)}
</Draggable>
If you want I can put this code to some sandbox to make it easier to debug.
I'm using the menu/menu item from material ui. It seems to have an issue if I try to render it based on a condition. Refer below...
const AddSelectItemButton = () => {
return (
<>
<Fab
aria-controls="simple-menu"
aria-haspopup="true"
onClick={handleClick}
className={classes.addButton}
size="medium"
color="primary"
aria-label="add"
>
<AddIcon />
</Fab>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleDelete}>Delete Item</MenuItem>
<MenuItem onClick={handleAddNew}>Add Item</MenuItem>
</Menu>
</>
)
}
Inside the main container I have something like this
return (
<div className='my-5'>
<Paper className="pl-5 pr-5 pb-5 position-relative">
<Typography className="pt-4 mb-4 text-center" variant="h4">My Items</Typography>
{!isAuthMode &&
<AddSelectItemButton />
}
<Grid container spacing={3} justify="center">
{allItems.items.map(item=>
<Grid key={item.id} item xs={5} className={`mt-4`} style={{height: '200px'}}>
<Card className={`${classes.root} d-flex ${classes.packInner}`}>
<CardActionArea className="d-flex">
<CardMedia
className={`${classes.media} ${classes.cardImage}`}
image={item.image}
title={item.brand}
/>
<CardContent className={classes.textContainer}>
<Typography gutterBottom variant="subtitle1">
{item.brand}
</Typography>
<Typography variant="body2" color="textSecondary">
{item.name}
</Typography>
<Typography variant="body2" color="textSecondary">
Weight: {item.weight}
</Typography>
<Typography variant="body2" color="textSecondary" className={classes.itemDescription}>
{packInfo.description.length > 80 ?
(`${packInfo.description.substring(0, 77) + '...'}`)
:
packInfo.description
}
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
)}
</Grid>
</Paper>
</div>
);
If I don't do the condition and include the code in the original rendering. The menu loads at the position of the button. With the condition, it renders far top left of the page and not at the button.
Anyone have an idea or need more info?
Thanks!
{!isAuthMode && (
<AddSelectItemButton />
)}
I have a card component:
<Card className="m-5 border-0 shadow" style={styles.card}>
<Row>
<Col>
<Card.Img src={props.image} style={styles.cardImage}/>
</Col>
<Col>
<Card.Body>
<Card.Title as="h1">
{props.title}
</Card.Title>
<Card.Text as="h4" style={styles.cardText}>
{props.description}
</Card.Text>
</Card.Body>
{
props.link &&
<Button style={styles.button} href={props.url}>Read More</Button>
}
</Col>
</Row>
</Card>
The card is wrapped in a fluid <Container> and <CardGroup> component from react-bootstrap:
<Container fluid className="text-center">
<CardGroup className="m-5 d-block">
<Card />
</CardGroup>
</Container>
On desktop device it looks like this:
But it looks like this on mobile device:
Here are the styles:
const styles = {
card: {
backgroundColor: '#B7E0F2',
borderRadius: 55,
padding: '3rem'
},
cardImage: {
height: '100%',
objectFit: 'cover',
borderRadius: 55
}
};
Does anyone know how to fix this? Thanks.
Try this. For the <Row> component class with className row in css file assign property as follows:
.row {
display: flex,
flex-wrap:wrap
}
Try this one
<Card.Columns>
<Card >
<Card.Body>
<Card.Title style={{textAlign:"center"}}>title</Card.Title>
<Card.Text style={{textAlign:"left"}}>
description
</Card.Text>
</Card.Body>
<Card.Footer>
<Card.Text style={{textAlign:"right"}}>Link</Card.Text>
</Card.Footer>
</Card>
</Card.Columns>
For more details check out this Link
These are my tabs and tables and I want to call different functions based on tabKey when you click on the tab.
<Paper className={classes.root} style = {{paddingTop:50}}>
<Grid>
<TabSelector
displayType="button"
showTab={"Org Details"}
showCount={false}
highlightTab={true}
onClick={() => this.getTabs.bind(this)}
>
<Tab name="Org Details" tabKey="gridOrgDetails">
<p>
<Grid>
<Paper className={classes.root} style={{ paddingTop: 50 }}>
<a href="#gridOrgDetails" id="gridOrgDetails" />
<Paper style={{ backgroundColor: "#759FEB" }}>
<Typography> ORG Details </Typography>
</Paper>
<EnhancedTable
checkBoxEnabled={false}
Data={{ rows: this.getOrg(), headCells: orgDeatils }}
rowsPerPage={5}
orderBy="Call_Date_vod__c"
order="desc"
/>
</Paper>
</Grid>
</p>
</Tab>
<Tab
name="License Details"
tabKey="gridLicenseDetails"
onClick={() => this.getLicenseDetails()}
>
<p>
<Grid>
<Paper className={classes.root} style={{ paddingTop: 50 }}>
<a href="#gridLicenseDetails" id="gridLicenseDetails" />
<Paper style={{ backgroundColor: "#759FEB" }}>
<Typography> License Details </Typography>
</Paper>
<EnhancedTable
checkBoxEnabled={false}
Data={{ rows: this.getOrg(), headCells: licenseDetails }}
rowsPerPage={5}
orderBy="Call_Date_vod__c"
order="desc"
/>
</Paper>
</Grid>
</p>
</Tab>
</TabSelector>;
This is my function where I am switching keys but this seems to be not working.
Can anyone please help me?
getTabs(f){
console.log(f.tabKey)
switch(f.tabKey) {
case "gridOrgDetails":
return this.getOrgDetails();
break;
case "gridLicenseDetails":
return this.getLicenseDetails();
break;
}
}
Here's a basic representation of what you're trying to achieve jsFiddle
link
const User = (props) => <div onClick = {props.onClick}>I am user
{props.user}</div>
class App extends React.Component {
constructor(props) {
super(props)
}
getTabs(f){
switch(f) {
case "gridOrgDetails":
console.log("gridOrgDetails")
break;
case "gridLicenseDetails":
console.log("gridLicenseDetails")
break;
}
}
render() {
return (
<div>
<div >
<User user="a" onClick={this.getTabs.bind(this,"gridOrgDetails")} />
<User user="b" onClick={this.getTabs.bind(this, "gridLicenseDetails")}/>
</div>
</div>
)
}
}
ReactDOM.render(<App />, document.querySelector("#app"))
I am stuck in this problem. I want to add/remove the class on a header element on scroll, but somehow I can not manage it.
I tried to mount and unmount (found few solutions here on Stack) but does not work in my case. Simply because in most of those cases the code relates to component but I have a little bit different set-up.
Here the full code:
https://codesandbox.io/s/angry-villani-lduor?fontsize=14
I want to add the new class on store_details_header
const handleChangeIndex = index => {
setValue(index);
};
if (!selectedStore) {
return null;
}
return (
<div className="store-details">
<div className="store-details__header" style={{ backgroundImage: `url(${selectedStore.headerBackgroundImgUrl})` }}>
<img className="store-details__header__exit" src={exit} alt="exit" onClick={backToNearYou} />
<img className="store-details__header__logo" src={selectedStore.headerLogoUrl} alt="logo" />
</div>
<div className="store-details__content" style={{ backgroundImage: `url(${selectedStore.contentBackgroundImgUrl})` }}>
<div>
<AppBar className={props.classes.root} position="static" color="default">
<Tabs value={value} classes={{ indicator: props.classes.indicator }} onChange={setSelectedNavigationItem} variant="fullWidth">
<StyledTab label="Products" />
<StyledTab label="Items" />
</Tabs>
</AppBar>
<SwipeableViews axis={'x'} index={value} onChangeIndex={handleChangeIndex}>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
</SwipeableViews>
</div>
</div>
{guestMode && renderGuestModeBox()}
{selectedStore.loyaltyCard && renderLoyaltyCard()}
</div>
);
};
const handleChangeIndex = index => {
setValue(index);
};
if (!selectedStore) {
return null;
}
return (
<div className="store-details">
<div className="store-details__header" style={{ backgroundImage: `url(${selectedStore.headerBackgroundImgUrl})` }}>
<img className="store-details__header__exit" src={exit} alt="exit" onClick={backToNearYou} />
<img className="store-details__header__logo" src={selectedStore.headerLogoUrl} alt="logo" />
</div>
<div className="store-details__content" style={{ backgroundImage: `url(${selectedStore.contentBackgroundImgUrl})` }}>
<div>
<AppBar className={props.classes.root} position="static" color="default">
<Tabs value={value} classes={{ indicator: props.classes.indicator }} onChange={setSelectedNavigationItem} variant="fullWidth">
<StyledTab label="Products" />
<StyledTab label="Items" />
</Tabs>
</AppBar>
<SwipeableViews axis={'x'} index={value} onChangeIndex={handleChangeIndex}>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
</SwipeableViews>
</div>
</div>
{guestMode && renderGuestModeBox()}
{selectedStore.loyaltyCard && renderLoyaltyCard()}
</div>
);
};