Close parent component - javascript

I have a code with which the user can select a file from their device. The Card component will display its name and operations that can be done with the file.
But my problem is that I don't know how to close this component if the user wants to cancel the action.
export default function DisplaySelectedFile() {
const [fileName, setFileName] = useState("");
console.log(setFileName)
return (
<div>
<SelectFileButton setFileName={setFileName} />
{fileName && <Card sx={styles.CommonStyle}>
<Stack spacing={10} direction="row" style={{paddingTop: "20px", paddingLeft: "10px"}}>
<div>{fileName}</div>
<Stack spacing={3} direction="row">
<div>Convert to</div>
<ConvertToFormatFile></ConvertToFormatFile>
</Stack>
<Button>CONVERT</Button>
<CloseIcon/>
</Stack>
</Card>}
</div>
);
}
I have added a button which should close the entire Card component. If I add the following code
<CloseIcon onClick={() => setFileName(false)}/>
If I add the following code, then the component closes. But the next time you select a file, this component does not open (only after reloading the page).
Tell me how to close the Card component correctly so that you can open it without problems

I would suggest to handle separately the card visibility and the file name value.
Something like this should work:
import React, { useState, useCallback } from "react";
const DisplaySelectedFile = () => {
const [fileName, setFileName] = useState(null);
const [showCard, setShowCard] = useState(false);
const handleSelectFile = useCallback(
(file) => {
setFileName(file);
file && setShowCard(true);
},
[setFileName, setShowCard]
);
const handleCloseCard = useCallback(() => {
setShowCard(false);
setFileName(null); // add this line only if it fits your use case
}, [setFileName, setShowCard]);
return (
<div>
<SelectFileButton setFileName={handleSelectFile} />
{showCard && (
<Card sx={styles.CommonStyle}>
<Stack
spacing={10}
direction="row"
style={{ paddingTop: "20px", paddingLeft: "10px" }}
>
<div>{fileName}</div>
<Stack spacing={3} direction="row">
<div>Convert to</div>
<ConvertToFormatFile></ConvertToFormatFile>
</Stack>
<Button>CONVERT</Button>
<CloseIcon onClick={handleCloseCard} />
</Stack>
</Card>
) || null}
</div>
);
}
export default DisplaySelectedFile;

Related

Show modal window without button press in react

I am doing a project and I want to show a modal window to compulsorily accept some Cookies.
I need that cookie window to be launched automatically, without pressing any button, when the application starts, that is, before the dashboard is loaded.
This is my code:
ModalCookie.js
imports ...
const style = {
position: 'absolute',
top: '50%',
left: '50%',
};
export default function CookiesModal() {
const handleOpen = () => setOpen(true);
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setCookiesPreview(false);
setOpen(false);
};
const handleNotClose = (event, reason) => {
if (reason && reason == "backdropClick")
return;
}
const [value, setValue] = React.useState('1');
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<ThemeProvider theme={theme}>
<div>
<Fade in={open}>
<Box>
<BootstrapDialog
onClose={handleNotClose}
aria-labelledby="customized-dialog-title"
open={open}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<BootstrapDialogTitle id="customized-dialog-title" onClose={handleClose}>
</BootstrapDialogTitle>
<TabContext value={value}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<TabList onChange={handleChange} aria-label="lab API tabs example">
<Tab
label="AAAAA"
value="1" />
</TabList>
</Box>
<TabPanel value="1">
<p>...</p>
</TabPanel>
</TabContext>
<Button
onClick={handleClose}
variant="contained"
color="secondary"
>
Aceptar
</Button>
</BootstrapDialog>
</Box>
</Fade>
</div>
</ThemeProvider>
);
}
Config.js
// COOKIES
export const setCookiesPreview = ( state ) => {
localStorage.setItem('cookiesPreview', state)
}
// --
export const isCookiesPreview = () => {
const active=localStorage.getItem('cookiesPreview') ? localStorage.getItem('cookiesPreview') : true;
setCookiesPreview(false);
return(
active
);
}
And my dashboard:
imports...
// MAIN
export const Dashboard = () => {
const state = useSelector( state => state);
console.log('isCookiesPreview='+isCookiesPreview());
if(isCookiesPreview()){
console.log('CookiesPreview ON ------------------------------------------------')
setTimeout(() => {
CookiesModal.handleOpen();
}, 15000);
}
return (
<>
<ThemeProvider theme={theme}>
<div>
<HeaderBar/>
{(alertMessage != null) && (alertMessage.length>0) ? <Alert severity={alertSeverity}>{alertMessage}</Alert> : <></>}
<Grid container item={true} xs={12}>
<BodyGrid/>
</Grid>
<Grid container item={true} xs={12} pt={4}>
<BottomBar/>
</Grid>
</div>
</ThemeProvider>
</>
)
I am trying to use the handleOpen() constant from ModalCookie.js to open the window from Dashboard.js and save the locale that those cookies have been accepted so as not to show it the following times
I can't get the window to show up, but it does show me the logs I've put on the Dashboard related to cookies.
It tells me that HandleOpen is not a function.

How do I render my dropdown menu in react-native?

I have a functional component Profile.js and on the header of that screen I put a button. Once this button is pressed I want to display a dropdown menu from react-native-material-menu
Part of my Profile.js:
function Profile(props) {
useLayoutEffect(() => {
props.navigation.setOptions({
headerRight: () => <HeaderRight />,
});
}
}, []);
My HeaderRight component:
export const HeaderRight = () => {
return (
<TouchableOpacity style={{ marginTop: 20, marginRight: 8 }}>
<Feather
name="more-vertical"
size={24}
color="black"
onPress={() => renderMenu()}
/>
</TouchableOpacity>
);
};
As you can see when the icon is pressed I call my renderMenu(), which looks like the following:
import React, { useState } from "react";
import { View, Text } from "react-native";
import { Menu, MenuItem, MenuDivider } from "react-native-material-menu";
export const renderMenu = (props) => {
const [visible, setVisible] = useState(true);
const hideMenu = () => setVisible(false);
const showMenu = () => setVisible(true);
return (
<View
style={{ height: "100%", alignItems: "center", justifyContent: "center" }}
>
<Menu
visible={visible}
anchor={<Text onPress={showMenu}>Show menu</Text>}
onRequestClose={hideMenu}
>
<MenuItem onPress={hideMenu}>Menu item 1</MenuItem>
<MenuItem onPress={hideMenu}>Menu item 2</MenuItem>
<MenuItem disabled>Disabled item</MenuItem>
<MenuDivider />
<MenuItem onPress={hideMenu}>Menu item 4</MenuItem>
</Menu>
</View>
);
};
When I render my page, I click on the header icon and I get the following error:
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:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
Can you tell me, how do I render my dropdown menu component?
You do not render the JSX on the return of an onPress function. Try this out:
export const HeaderRight = () => {
const [visible, setVisible] = useState(false);
let toggle = () => setVisible(!visible);
return (
<>
<TouchableOpacity style={{ marginTop: 20, marginRight: 8 }}>
<Feather
name="more-vertical"
size={24}
color="black"
onPress={toggle}
/>
</TouchableOpacity>
<Menu
visible={visible}
anchor={<Text onPress={toggle}>Show menu</Text>}
onRequestClose={toggle}>
<MenuItem onPress={toggle}>Menu item 1</MenuItem>
<MenuItem onPress={toggle}>Menu item 2</MenuItem>
<MenuItem disabled>Disabled item</MenuItem>
<MenuDivider />
<MenuItem onPress={toggle}>Menu item 4</MenuItem>
</Menu>
</>
);
};

Changing "likes" based on what picture is shown

I am making an app based off Nasa's api that shows a picture or video each day. I have also created a like button that toggles if a person clicks it to like a picture or to toggle it back to default. I created the app in a way where a user can select a date using a calendar component that is through material-ui and when they select a date, it will bring the picture or video from that date. I am trying to figure out how to attach the like button to each picture, so that if they like one picture, they can go to another day and it will let them like another picture. Currently, for example, if I like today's picture, select the calendar and go to yesterday's picture, my like button is still toggled. Here is the code I used for getting the pictures and other information to show:
export default function PictureOfDay(props) {
const [picture, setPicture] = useState([])
const {date} = props;
let selectDate = moment(date, "ddd MMM DD YYYY HH:mm:ss Z-HHmm");
let formatDate = selectDate.format("YYYY-MM-DD");
useEffect(() => {
axios.get(
`https://api.nasa.gov/planetary/apod?api_key=QQpTYaQHDUvPAyVorMgxfKhQEoSQikBYt5WuFCf6&date=${formatDate}`
)
.then((response) => {
console.log(response.data);
setPicture(response.data);
})
.catch((err) => {
console.log(err)
});
}, [formatDate]);
return (
<div className="info">
{props.fetchingData && (
<div className="key spinner">
<Loader type="Puff" color="#800080" height="60" width="60" />
<p>Loading Data</p>
</div>
)}
<PictureInfo
date={picture.date}
title={picture.title}
image={picture.url}
media={picture.media_type}
explanation={picture.explanation}
/>
</div>
);
}
I also have my Like button logic on a different component. Right now, it is not attached to the pictures and I am unsure how to go about doing that:
import React, {useState, useEffect} from "react";
import ToggleHearts from "./ToggleHearts"
import {
Button,
Typography,
} from "#mui/material";
import {makeStyles} from "#mui/styles";
const useStyles = makeStyles((theme) => ({
button: {
...theme.typography.buttons,
fontFamily: "Orbitron",
padding: "0.7em",
fontSize: "1.5em",
width: "3.2em",
height: "3.2em",
background: theme.palette.primary.mainGradient,
border: "2px solid pink",
"&:hover": {
background: theme.palette.secondary.mainGradient,
},
},
}));
const Likes = () => {
const classes = useStyles();
const [liked, setLiked] = useState(false)
const handleChangeHeart = () => {
setLiked((previousHeart) => {
return !previousHeart;
});
};
useEffect(() => {
setLiked(JSON.parse(window.localStorage.getItem("liked")));
}, [])
useEffect(() => {
window.localStorage.setItem('liked', liked);
}, [liked])
return (
<Button
className={classes.button}
variant="contained"
onClick={handleChangeHeart}
>
<Typography style={{ fontFamily: "Orbitron" }}>
<ToggleHearts liked={liked}/>
</Typography>
</Button>
);
}
export default Likes
The Likes component is just attached to my component that renders everything on the page, here is the code to that:
export default function PictureInfo(props) {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
const newDate = moment(props.date).format("dddd, MMMM, Do YYYY");
return (
<React.Fragment>
<Grid
container
direction="row"
justifyContent="center"
alignItems="center"
>
<Grid item className={classes.formGridItem}>
<Typography variant="h2">Date: {newDate}</Typography>
</Grid>
<Grid item className={classes.formGridItem}>
<Typography variant="h2">Title of Photo: {props.title}</Typography>
</Grid>
</Grid>
<Grid
container
direction="column"
justifyContent="center"
alignItems="center"
>
<Grid item className={classes.formGridItem}>
{props.media === "video" ? (
<iframe
className={classes.image}
title="video"
src={props.image}
width="800px"
height="600px"
></iframe>
) : (
<img className={classes.image} alt="nasa" src={props.image} />
)}
</Grid>
<Likes />
<Grid item className={classes.formGridItem} align="center">
<Button
className={classes.button}
variant="contained"
onClick={handleOpen}
>
Click here for more information!
</Button>
</Grid>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<Typography
id="modal-modal-title"
style={{
borderBottom: "1px solid pink",
fontFamily: "'Orbitron', sans-serif",
marginBottom: "1em",
fontSize: "1.4em",
}}
>
Explanation of: {props.title}
</Typography>
<Box
style={{
background: "white",
border: "1px solid purple",
padding: "2em",
}}
>
<Typography
id="modal-modal-description"
variant="subtitle2"
style={{ fontSize: "1.2em" }}
>
{props.explanation}
</Typography>
</Box>
</Box>
</Modal>
<footer>
<Typography
variant="subtitle2"
style={{ fontSize: "1rem", color: "black" }}
>
©2021 Charlene Johnson
</Typography>
</footer>
</Grid>
</React.Fragment>
);
}
If i right to understand you
all picture or video posts, must have an unique ID in you data represent, you data for this must look like this for example:
[{
id:'id of post',
likes:[idOfUsers],
...other needed for you data
}]
So, now you can check for likes id of user, and toggle you 'like button', if ID of user exist in this post into a 'likes' array,
or store IDs of posts to 'postsWhichwasLiked':[idsOfPosts],
and then to define which of posts was liked across getting id from this array and then to comparing with ID of post

React Hook useState value being reset to initial value

The state of a value set using React useState hook gets set to the proper value and then reset to null. Critical code below. The click event that sets the startDate to the current date and time is 3 components down from where startDate is initialized. When setStartDate did not work I created an arrow function, updateStartDate. Both had the same problem where the startDate was changed after the click event (witnessed per the console.log in the top component), but was null just before the next click event (per the console.log in the click event). This is not an async problem as I see the change made before subsequent click.
If this is something that just does not work please explain. I could probably fix with useReducer but prefer to keep the useState if there is something I can do to correct this... If not correctable then I would like to at least understand why it does not work so that I can avoid this problem in the future.
export const DisplayTicTacToeContainer = (props) => {
const [startDate, setStartDate]= useState();
const updateStartDate = (newDate) => {
setStartDate(newDate);
}
useEffect (() => {
setStartDate(null);
}, []);
useEffect(() => {
console.log( "displayTicTacToeContainer useEffect for change of startDate = ", startDate)
}, [startDate]);
return (
<DisplayTicTacToeMatch arrayOfMatchingItems ={arrayOfMatchingItems}
startDate={startDate}
setStartDate={setStartDate}
updateStartDate={updateStartDate}
/>);
}
//-----------------------------------------------
export const DisplayTicTacToeMatch = (props) => {
const { startDate,
setStartDate,
updateStartDate,
} = props;
useEffect(() => {
// Performs some prep and working fine.
}, []);
return (
<TicTacToe
startDate={startDate}
setStartDate={setStartDate}
updateStartDate={updateStartDate}
/>
);
}
//-----------------------------------------------
const TicTacToeContainer = (props) => {
const { startDate,
setStartDate,
updateStartDate,
} = props;
const [board, setBoard] = useState(<Board
updateStartDate={updateStartDate}
startDate={startDate}
setStartDate={setStartDate}/>);
return (
<Board/>
)
}
export default TicTacToeContainer;
I renamed the component to BoardComponent and the state variable to boardLayout. I included the full return portion of the BoardComponent below.
As I am still experiencing the problem I would agree with you that, "DisplayTicTacToeContainer is being mounted twice". Any thoughts on how I can avoid this from happening?
Other than this inability to setStartDate, everything is working fine.
//-----------------------------------------------
const Board = (props) => {
const { updateStartDate,
startDate,
setStartDate,
} = props;
return (
<>
<Grid container maxwidth="lg" alignItems="center" spacing={1}>
<Grid item xs={9}>
<Grid container alignItems="center">
<Grid item xs={9}>
<Typography variant = "body1">
First select a square. Once the "Inquiry" word or phrase appears below, find
the correct response in the column on the right and select that buttton. A correct
response will fill the square previously selected with an "O" or "X".
</Typography>
<div style={{ width: '100%' }}>
<Box
display="flex"
flexWrap="wrap"
p={1}
m={1}
bgcolor="background.paper"
css={{ maxWidth: 900 }}
>
<Box p={1} bgcolor="grey.300">
Inquiry : {inquiry}
</Box>
</Box>
<Box
display="flex"
flexWrap="wrap"
p={1}
m={1}
bgcolor="background.paper"
css={{ maxWidth: 900 }}
>
<Box p={1} bgcolor="grey.300">
Next move by : {currentPlayer}
</Box>
<Box p={1} bgcolor="grey.300">
{showStatus}
</Box>
</Box>
</div>
</Grid>
</Grid>
<MyAux>
{boardLayout.map((row, rowId) => {
const columns = row.map((column, columnId) => (
<Grid key={columnId} item>
<ButtonBase >
<Paper
onClick={(e) => {
clickSquareHandler(e);
}}
elevation={4}
data-coord={rowId + ':' + columnId}
id={"Square" + rowId.toString() + columnId.toString()}
className={classes.Paper}>
<Icon
className={classes.Icon}
style={{fontSize: 78}}>
</Icon>
</Paper>
</ButtonBase>
</Grid>
));
return (
<Grid
key={rowId}
className={classes.Grid}
container
spacing={2}>
{columns}
</Grid>)
})}
</MyAux>
</Grid>
<Grid item xs={3} >
<Paper className={classes.paper}>
<Typography variant = "body1">
Response Options
</Typography>
<ButtonGroup
orientation="vertical"
color="secondary"
aria-label="vertical outlined secondary button group"
>
{responseChoices.map((choice) => (
<Controls.Button
key ={choice.value}
text={choice.value}
variant="contained"
color = "secondary"
onClick={() => {
chooseChecker(choice);
}}
className={
response && response.value === choice.value ? "selected" : ""
}
disabled={!!selected[choice.value]}
fullWidth = "true"
size = "small"
/>
))}
</ButtonGroup>
</Paper>
</Grid>
</Grid>
</>
)
}
BoardContainer.propTypes = {
won: PropTypes.func,
size: PropTypes.number
};
export default BoardContainer;
At least, code below doesn't make much sense.
Please don't set state value as a component.
Also, try to name state variable different from components, since it will confuse you at some ppint.
const [board, setBoard] = useState(<Board
updateStartDate={updateStartDate}
startDate={startDate}
setStartDate={setStartDate}/>);
return (
<Board/>
)
Another possibility is that the DisplayTicTacToeContainer is being mounted twice, but I can't confirm it with the code provided.

How to handle multiple menu state with Material-UI Menu component?

I have a dynamically generated set of dropdowns and accordions that populate at render client-side (validated user purchases from db).
I'm running into an error that I'm sure comes from my menu anchorEl not knowing 'which' menu to open using anchorEl. The MUI documentation doesn't really cover multiple dynamic menus, so I'm unsure of how to manage which menu is open
Here is a pic that illustrates my use-case:
As you can see, the menu that gets anchored is actually the last rendered element. Every download button shows the last rendered menu. I've done research and I think I've whittled it down to the anchorEl and open props.
Here is my code. Keep in mind, the data structure is working as intended, so I've omitted it to keep it brief, and because it's coming from firebase, I'd have to completely recreate it here (and I think it's redundant).
The component:
import { useAuth } from '../contexts/AuthContext'
import { Accordion, AccordionSummary, AccordionDetails, Button, ButtonGroup, CircularProgress, ClickAwayListener, Grid, Menu, MenuItem, Typography } from '#material-ui/core'
import { ExpandMore as ExpandMoreIcon } from '#material-ui/icons'
import LoginForm from '../components/LoginForm'
import { motion } from 'framer-motion'
import { useEffect, useState } from 'react'
import { db, functions } from '../firebase'
import styles from '../styles/Account.module.scss'
export default function Account() {
const { currentUser } = useAuth()
const [userPurchases, setUserPurchases] = useState([])
const [anchorEl, setAnchorEl] = useState(null)
const [generatingURL, setGeneratingURL] = useState(false)
function openDownloads(e) {
setAnchorEl(prevState => (e.currentTarget))
}
function handleClose(e) {
setAnchorEl(prevState => null)
}
function generateLink(prefix, variationChoice, pack) {
console.log("pack from generate func", pack)
setGeneratingURL(true)
const variation = variationChoice ? `${variationChoice}/` : ''
console.log('link: ', `edit-elements/${prefix}/${variation}${pack}.zip`)
setGeneratingURL(false)
return
if (pack.downloads_remaining === 0) {
console.error("No more Downloads remaining")
setGeneratingURL(false)
handleClose()
return
}
handleClose()
const genLink = functions.httpsCallable('generatePresignedURL')
genLink({
fileName: pack,
variation: variation,
prefix: prefix
})
.then(res => {
console.log(JSON.stringify(res))
setGeneratingURL(false)
})
.catch(err => {
console.log(JSON.stringify(err))
setGeneratingURL(false)
})
}
useEffect(() => {
if (currentUser !== null) {
const fetchData = async () => {
// Grab user products_owned from customers collection for user UID
const results = await db.collection('customers').doc(currentUser.uid).get()
.then((response) => {
return response.data().products_owned
})
.catch(err => console.log(err))
Object.entries(results).map(([product, fields]) => {
// Grabbing each product document to get meta (title, prefix, image location, etc [so it's always current])
const productDoc = db.collection('products').doc(product).get()
.then(doc => {
const data = doc.data()
const productMeta = {
uid: product,
title: data.title,
main_image: data.main_image,
product_prefix: data.product_prefix,
variations: data.variations
}
// This is where we merge the meta with the customer purchase data for each product
setUserPurchases({
...userPurchases,
[product]: {
...fields,
...productMeta
}
})
})
.catch(err => {
console.error('Error retrieving purchases. Please refresh page to try again. Full error: ', JSON.stringify(err))
})
})
}
return fetchData()
}
}, [currentUser])
if (userPurchases.length === 0) {
return (
<CircularProgress />
)
}
return(
currentUser !== null && userPurchases !== null ?
<>
<p>Welcome, { currentUser.displayName || currentUser.email }!</p>
<Typography variant="h3" style={{marginBottom: '1em'}}>Purchased Products:</Typography>
{ userPurchases && Object.values(userPurchases).map((product) => {
const purchase_date = new Date(product.purchase_date.seconds * 1000).toLocaleDateString()
return (
<motion.div key={product.uid}>
<Accordion style={{backgroundColor: '#efefef'}}>
<AccordionSummary expandIcon={<ExpandMoreIcon style={{fontSize: "calc(2vw + 10px)"}}/>} aria-controls={`${product.title} accordion panel`}>
<Grid container direction="row" alignItems="center">
<Grid item xs={3}><img src={product.main_image} style={{ height: '100%', maxHeight: "200px", width: '100%', maxWidth: '150px' }}/></Grid>
<Grid item xs={6}><Typography variant="h6">{product.title}</Typography></Grid>
<Grid item xs={3}><Typography variant="body2"><b>Purchase Date:</b><br />{purchase_date}</Typography></Grid>
</Grid>
</AccordionSummary>
<AccordionDetails style={{backgroundColor: "#e5e5e5", borderTop: 'solid 6px #5e5e5e', padding: '0px'}}>
<Grid container direction="column" className={styles[`product-grid`]}>
{Object.entries(product.packs).map(([pack, downloads]) => {
// The pack object right now
return (
<Grid key={ `${pack}-container` } container direction="row" alignItems="center" justify="space-between" style={{padding: '2em 1em'}}>
<Grid item xs={4} style={{ textTransform: 'uppercase', backgroundColor: 'transparent' }}><Typography align="left" variant="subtitle2" style={{fontSize: 'calc(.5vw + 10px)'}}>{pack}</Typography></Grid>
<Grid item xs={4} style={{ backgroundColor: 'transparent' }}><Typography variant="subtitle2" style={{fontSize: "calc(.4vw + 10px)"}}>{`Remaining: ${downloads.downloads_remaining}`}</Typography></Grid>
<Grid item xs={4} style={{ backgroundColor: 'transparent' }}>
<ButtonGroup variant="contained" fullWidth >
<Button id={`${pack}-btn`} disabled={generatingURL} onClick={openDownloads} color='primary'>
<Typography variant="button" style={{fontSize: "calc(.4vw + 10px)"}} >{!generatingURL ? 'Downloads' : 'Processing'}</Typography>
</Button>
</ButtonGroup>
<ClickAwayListener key={`${product.product_prefix}-${pack}`} mouseEvent='onMouseDown' onClickAway={handleClose}>
<Menu anchorOrigin={{ vertical: 'top', horizontal: 'right' }} transformOrigin={{ vertical: 'top', horizontal: 'right' }} id={`${product}-variations`} open={Boolean(anchorEl)} anchorEl={anchorEl}>
{product.variations && <MenuItem onClick={() => generateLink(product.product_prefix, null, pack) }>{`Pack - ${pack}`}</MenuItem>}
{product.variations && Object.entries(product.variations).map(([variation, link]) => {
return (
<MenuItem key={`${product.product_prefix}-${variation}-${pack}`} onClick={() => generateLink(product.product_prefix, link, pack)}>{ variation }</MenuItem>
)
})}
</Menu>
</ClickAwayListener>
</Grid>
</Grid>
)}
)}
</Grid>
</AccordionDetails>
</Accordion>
</motion.div>
)
})
}
</>
:
<>
<p>No user Signed in</p>
<LoginForm />
</>
)
}
I think it also bears mentioning that I did check the rendered HTML, and the correct lists are there in order - It's just the last one assuming the state. Thanks in advance, and please let me know if I've missed something, or if I can clarify in any way. :)
i couldn't manage to have a menu dynamic,
instead i used the Collapse Panel example and there i manipulated with a property isOpen on every item of the array.
Check Cards Collapse Example
On the setIsOpen method you can change this bool prop:
const setIsOpen = (argNodeId: string) => {
const founded = tree.find(item => item.nodeId === argNodeId);
const items = [...tree];
if (founded) {
const index = tree.indexOf(founded);
founded.isOpen = !founded.isOpen;
items[index]=founded;
setTree(items);
}
};
<IconButton className={clsx(classes.expand, {
[classes.expandOpen]: node.isOpen,
})}
onClick={()=>setIsOpen(node.nodeId)}
aria-expanded={node.isOpen}
aria-label="show more"
>
<MoreVertIcon />
</IconButton>
</CardActions>
<Collapse in={node.isOpen} timeout="auto" unmountOnExit>
<CardContent>
<MenuItem onClick={handleClose}>{t("print")}</MenuItem>
<MenuItem onClick={handleClose}>{t("commodities_management.linkContainers")}</MenuItem>
<MenuItem onClick={handleClose}>{t("commodities_management.linkDetails")}</MenuItem>
</CardContent>
</Collapse>
I think this is the right solution for this: https://stackoverflow.com/a/59531513, change the anchorEl for every Menu element that you render. :D
This code belongs to TS react if you are using plain JS. Then remove the type.
import Menu from '#mui/material/Menu';
import MenuItem from '#mui/material/MenuItem';
import { useState } from 'react';
import { month } from '../../helper/Utilities';
function Company() {
const [anchorEl, setAnchorEl] = useState<HTMLElement[]>([]);
const handleClose = (event: any, idx: number) => {
let array = [...anchorEl];
array.splice(idx, 1);
setAnchorEl(array);
};
<div>
{month &&
month.map((val: any, ind: number) => {
return (
<div
key={val.id + 'w9348w344ndf allBankAndCardAccountOfClient'}
style={{ borderColor: ind === 0 ? '#007B55' : '#919EAB52' }}
>
<Menu
id='demo-positioned-menu'
aria-labelledby='demo-positioned-button'
anchorEl={anchorEl[ind]}
open={anchorEl[ind] ? true : false}
key={val.id + 'w9348w344ndf allBankAndCardAccountOfClient' + ind}
onClick={(event) => handleClose(event, ind)}
anchorOrigin={{
vertical: 'top',
horizontal: 'left',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
>
<MenuItem
key={val.id + 'w9348w344ndf allBankAndCardAccountOfClient' + ind}
onClick={(event) => handleClose(event, ind)}
style={{
display: ind === 0 ? 'none' : 'inline-block',
}}
>
<span
style={{
marginLeft: '.5em',
color: 'black',
background: 'inherit',
}}
>
Make Primary
</span>
</MenuItem>
<MenuItem onClick={(event) => handleClose(event, ind)}>
<span style={{ marginLeft: '.5em', color: 'black' }}>Edit</span>
</MenuItem>
<MenuItem
onClick={(event) => handleClose(event, ind)}
style={{
display: ind === 0 ? 'none' : 'inline-block',
}}
>
<span style={{ marginLeft: '.5em', color: 'red' }}>Delete</span>
</MenuItem>
</Menu>
</div>
);
})}
</div>;
}
export default Company;

Categories