REACT- Popover doesn't display my json content - javascript

In menu/ the name of my invited people are not diplayed there is only the InfoIcon in the Cell. I want to create a Popover, when you click on the InfoIcon, you get all the info of the invited people(name and location).
export default function Display() {
const { dishes } = JsonData;
const [anchor, setAnchor] = useState(null);
const openPopover = (event) => {
setAnchor(event.currentTarget);
};
const data = useMemo(
() => [
...
{
//Problem: participants not displayed and click not working
Header: "Invited",
id: "invited",
accessor: (row) => row.invited.map(({ name }) => name).join(", "),
Cell: (props) => (
<div>
<InfoIcon />
<Popover
open={Boolean(anchor)}
anchorEl={anchor}
anchorOrigin={{
vertical: "top",
horizontal: "left"
}}
transformOrigin={{
vertical: "bottom",
horizontal: "right"
}}
>
<Typography variant="h1">{props.participants}</Typography>
</Popover>
</div>
)
},
],
[]
);
return (
<Table
data={dishes}
columns={data}
/>
);
}
Here is my code

In addition to saving the clicked element into state so the Popover component has an element ref it needs to also store in state which specific row's participants to render into the popover. Currently the code is using a singular boolean value for all the popovers. Use the row.id to open a specific popover.
Don't forget to add the "anchor" state to the dependency array so the popover gets the latest state.
function Display() {
const { menus } = JsonData;
const [anchorId, setAnchorId] = useState(null);
const [anchorEl, setAnchorEl] = useState(null);
const openPopover = id => (event) => {
setAnchorId(id);
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorId(null);
setAnchorEl(null);
};
const data = useMemo(
() => [
{
Header: "Id",
accessor: (row) => row.id
},
{
Header: "Invited",
id: "invited",
accessor: (row) => row.invited,
Cell: (props) => (
<div>
{props.value.map(({ name }) => name).join(", ")}
<InfoIcon onClick={openPopover(props.row.id)} />
<Popover
open={anchorId === props.row.id}
onClose={handleClose}
anchorEl={anchorEl}
anchorOrigin={{
vertical: "top",
horizontal: "left"
}}
transformOrigin={{
vertical: "bottom",
horizontal: "right"
}}
>
<Typography variant="h6">
{props.value.map(({ name, location }) => (
<div key={name}>
<p>{name}</p>
<p>Location: {location}</p>
</div>
))}
</Typography>
</Popover>
</div>
)
},
{
Header: "Title",
accessor: (row) => ({ title: row.title, id: row.id }),
Cell: ({ value }) => (
<Link to={{ pathname: `/menu/${value.id}` }}>{value.title}</Link>
)
}
],
[anchorEl, anchorId]
);
const initialState = {
sortBy: [
{ desc: false, id: "id" },
{ desc: false, id: "invited" },
{ desc: false, id: "title" }
]
};
return (
<Table
data={menus}
columns={data}
initialState={initialState}
withCellBorder
withRowBorder
withSorting
withPagination
/>
);
}

Related

MUI DesktopDatePicker as edit component closes on change

I have an MUI table and I made it editable with custom component. However, I am having problem with the MUI DesktopDatePicker. Whenever I change the value of the date, picking from the calendar or manual input, the component just closes. I think it might be due to the fact that I am using useState as it triggers a re-render. I have tried using useRef which would not cause the component to close but the value won't be updated when picking from calendar. Also, the default value of the date component should be the current value of the date in the selected row. Right now, I am using new Date() as a default.
this is the code for my column:
const [dateValue, setDateValue] = React.useState(new Date());
const handleDateChange = (newValue) => {
setDateValue(newValue)
}
const columns = [
{
title: "Sequence",
field: "sequence",
editable: "never",
render: rowData => {
return (
<Typography>
{rowData.sequence }
</Typography >
)
},
},
{
title: "Activity Name",
field: "activityName",
editable: "never",
render: rowData => {
return (
<Typography>
{rowData.activityName}
</Typography >
)
},
},
{
title: "Date",
field: "activityDate",
render: rowData => {
return (
<Typography>
{ rowData.activityDate ? moment(rowData.activityDate).format('DD-MMM-yyyy') : '' }
</Typography >
)
},
editComponent: (props) => (
<DesktopDatePicker
label="Date"
inputFormat="dd/MMM/yyyy"
value={ dateValue}
onChange={ handleDateChange }
renderInput={(params) => <TextField {...params} />}
/>
)
},
{
title: "Cost (Import)",
field: "costImport",
editable: "never",
render: rowData => {
return (
<Typography>
{ rowData.costImport ? (rowData.costImport)?.toLocaleString('en', {maximumFractionDigits: 2, minimumFractionDigits: 2 }) : '' }
</Typography >
)
},
},
{
title: "Cost",
field: "cost",
render: rowData => {
return (
<Typography>
{rowData.cost ? Number(rowData.cost)?.toLocaleString('en', { maximumFractionDigits: 2, minimumFractionDigits: 2 }) : '' }
</Typography >
)
},
editComponent: (props) => {
return (
<TextField
type="number"
decimalScale='2'
value={props.rowData.cost}
onChange={e => props.onChange(e.target.value)}
defaultValue={props.rowData.cost}
/>
)
}
},
{
title: "Status",
field: "activityStatus",
render: rowData => {
return (
<Typography>
{rowData.activityStatus ? rowData.activityStatus : ''}
</Typography >
)
},
editComponent: (props) => {
return (
<Select
value={props.rowData.activityStatus}
onChange={e => props.onChange(e.target.value)}
>
<MenuItem value={'Canceled'}>Cancled</MenuItem>
<MenuItem value={'Finish'}>Finish</MenuItem>
<MenuItem value={'Open'}>Open</MenuItem>
<MenuItem value={'Process'}>Process</MenuItem>
</Select>
)
}
},
];
Image of UI after selecting date from calendar:

value not loading initially in datagrid

I'm trying to fetch data using api and show the data in my datagrid. but initially the data is not loading. though I can get the data, and I don't know why it doesn't show in the datagrid. What I'm actually doing is, I have a common function for datagrid along with search option in one file. I'm getting the getting the data in another file. Now everytime I make a change and save the file, it shows the data, but when I refresh the page the data is not showing again. kindly help me figure out. Thanks in advance
this the code where I'm getting the data
const columns = [
{ field: 'role', headerName: 'Role', },
{ field: 'counterParty', headerName: 'Counter Party', },
{ field: 'tokens', headerName: 'Token', },
{ field: 'date', headerName: 'Date', },
{ field: 'comment', headerName: 'Comments', }
];
export default function TransactionCard(props) {
const [TransactionData, setTransactionData] = useState([]);
const [loading, setLoading] = useState(true);
// setLoading(loading, true);
useEffect(() => {
axios.get('http://localhost:8006/api/v2/user/transactions').then(function (res) {
try {
var result = res.data;
// console.log(result.data.data)
setTransactionData(result.data.data)
// setLoading(false);
}
catch (error) {
console.log(error)
}
})
}, [])
console.log(TransactionData)
return (
<>
<Card {...props}>
<CardContent>
<DataGridHelper title='Transaction' rows={TransactionData} columns={columns} />
</CardContent>
</Card>
</>
);
}
This is Where I'm getting the data
const DataGridHelper = ({ rows, columns, title }) => {
const [platform, setPlatform] = useState([]);
const [searchText, setSearchText] = useState('');
const [Rows, setRows] = useState([]);
useEffect(() => {
setPlatform(rows);
setRows(rows);
}, []);
console.log(Rows);
function escapeRegExp(value) {
return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
const requestSearch = (searchValue) => {
const searchRegex = new RegExp(escapeRegExp(searchValue), 'i');
const filteredRows = platform.filter((row) => {
return Object.keys(row).some((field) => {
return searchRegex.test(row[field].toString());
});
});
setRows(filteredRows);
};
console.log(rows)
return (
<>
<Stack direction="row" alignItems="center" justifyContent='space-between' gap={1}>
<Stack direction="row" alignItems="center" gap={1}>
<RuleIcon sx={{ color: "text.secondary" }} />
<Typography sx={{ fontSize: 16, fontWeight: 'bold' }} color="text.secondary" gutterBottom>
{title}
</Typography></Stack>
<Box sx={{ flexDirection: 'column' }}>
<TextField
variant="outlined"
size='small'
value={searchText}
onChange={(e) => { setSearchText(e.target.value); requestSearch(e.target.value) }}
placeholder="Search..."
InputProps={{
startAdornment: <SearchIcon fontSize="small" color="action" />,
endAdornment: (
<IconButton
title="Clear"
aria-label="Clear"
size="small"
style={{ visibility: searchText ? 'visible' : 'hidden', borderRadius: "57%", paddingRight: "1px", margin: "0", fontSize: "1.25rem" }}
onClick={(e) => { setSearchText(''); setRows(platform) }}
>
<ClearIcon fontSize="small" color="action" />
</IconButton>
),
}}
sx={{
width: { xs: 1, sm: 'auto' }, m: (theme) => theme.spacing(1, 0.5, 1.5),
'& .MuiSvgIcon-root': {
mr: 0.5,
},
'& .MuiInput-underline:before': {
borderBottom: 1,
borderColor: 'divider',
},
}}
/>
</Box>
</Stack>
<div style={{ height: 250, width: '100%' }}>
<DataGrid
disableColumnMenu
rows={Rows}
columns={columns}
pageSize={10}
rowsPerPageOptions={[10]}
/>
</div>
</>
);
}
export default DataGridHelper
this is the data I'm getting initially
first of all, your code is so dirty :), i cant test your code cause its have your rest API and you don't name consoles, i just understand which one is result of axios, but i think your mistake is on useEffect depandecies in DataGridHelper you must write rows in it, and second maybe in useEffect when you get data in rest API you might write if condition for try in axios tell that if(!!result.data.data) then do that i think it must your problem
useEffect(() => {
setPlatform(rows);
setRows(rows);
}, [rows]);
and :
useEffect(() => {
axios.get('http://localhost:8006/api/v2/user/transactions').then(function (res) {
try {
if(!!res.data){
var result = res.data;
// console.log(result.data.data)
setTransactionData(result.data.data)
// setLoading(false);
}
}
catch (error) {
console.log(error)
}
})
}, [])

React Event Handling For Each Icon

How can I make handleclick operation unique for each icon? For example when click to plus icon, color of all changes to green. But I want only plus icon to change into green.
const [isActive, setIsActive] = useState(false);
const handleClick = () => {
setIsActive((current) => !current);
};
return (
<div className="list-icons">
<FaPlus
className="plus-icon"
style={{
color: isActive ? "green" : "",
}}
onClick={handleClick}
/>
<FaCheck
className="check-icon"
style={{
color: isActive ? "green" : "",
}}
onClick={handleClick}
/>
<FaHeart
className="heart-icon"
style={{
color: isActive ? "green" : "",
}}
onClick={handleClick}
/>
</div>
)
The best way to do that is that you should create an array of object for your icons.
For example
const [icons, setIcons] = useState([
{
id: 1,
icon: FaPlus,
className:"plus-icon",
isActive: false,
},
{
id: 2,
icon: FaCheck,
className:"check-icon",
isActive: false,
},
{
id: 3,
icon: FaHeart,
className:"heart-icon",
isActive: false,
},
]);
const handleClick = (id: number) => {
const newIcons = icons.map((icon) => {
if(icon.id === id) {
return {
...icon,
isActive: !icon.isActive,
}
}
return icon;
});
setIcons(newIcons);
};
return (
<div className="list-icons">
{icons.map((icon) => {
const Icon = icon.icon
return (
(
<Icon
className={icon.className}
style={{
color: icon.isActive ? "green" : "",
}}
onClick={() => handleClick(icon.id}
/>
)
})
</div>
)
You should use an array of boolean:
const [isActive, setIsActive] = useState([false, false, false]);
const handleClick = (index) => {
setIsActive((current) => {
current[index] = !current[index];
return current;
});
};
return (
<div className="list-icons">
<FaPlus
className="plus-icon"
style={{
color: isActive[0] ? "green" : "",
}}
onClick={() => handleClick(0)}
/>
<FaCheck
className="check-icon"
style={{
color: isActive[1] ? "green" : "",
}}
onClick={() => handleClick(1)}
/>
<FaHeart
className="heart-icon"
style={{
color: isActive[2] ? "green" : "",
}}
onClick={() => handleClick(2)}
/>
</div>
)
const icons = ['plus', 'check', 'heart'];
const components = [<FaPlus />, <FaCheck />, <FaHeart />];
const [activeIcons, setActiveIcons] = useState(icons.map(() => false));
const onActiveToggle = (index) => {
setActiveIcons(prev => {
prev[index] = !prev[index];
return prev;
});
}
const iconProps = useMemo(() => {
return icons.map((icon, index) => ({
className: `${icon}-icon`,
style: {{ color: activeIcons[index] ? 'green': 'black' }},
onClick: () => onActiveToggle(index)
})
}, [activeIcons]);
return (
<>
{components.map((Component, index) => (
<Component {...iconProps[index]}/>
))}
</>
);

Changing the Color of the Drawer in Material-UI React

I want to change the background color of my MUI drawer. Here is my header code:
import { AppBar, Toolbar, Typography, makeStyles, Button, IconButton, Drawer, Link, MenuItem } from "#material-ui/core";
import React, { useEffect, useState } from "react";
import { Link as RouterLink } from "react-router-dom";
import MenuIcon from "#material-ui/icons/Menu";
import logo from "./Icon.png";
const useStyles = makeStyles (() => ({
header: {
backgroundColor: "#1b1b1b",
paddingRight: "0px",
paddingLeft: "18px",
"#media (max-width: 900px)": {
paddingLeft: 0,
},
},
menuButton: {
fontFamily: "Inter, sans-serif",
fontWeight: 700,
size: "18px",
marginLeft: "38px",
},
toolbar: {
display: "flex",
justifyContent: "space-between",
},
drawerContainer: {
padding: "20px 30px",
color: "inherit",
},
}));
const headersData = [
{
label: "Featured",
href: "/featured",
},
{
label: "Favorites",
href: "/favorites",
},
{
label: "My Account",
href: "/account",
},
{
label: "Discord",
href: "/discord",
}
];
export default function Header() {
const [state, setState] = useState({
mobileView: false,
drawerOpen: false
});
const { mobileView, drawerOpen } = state;
useEffect(() => {
const setResponsivness = () => {
return window.innerWidth < 900
? setState((prevState) => ({ ...prevState, mobileView: true }))
: setState((prevState) => ({ ...prevState, mobileView: false, drawerOpen: false }));
};
setResponsivness();
window.addEventListener("resize", () => setResponsivness());
return () => {
window.removeEventListener("resize", () => setResponsivness());
}
}, []);
const { header, menuButton, toolbar, drawerContainer } = useStyles();
const displayDesktop = () => {
return (
<Toolbar className={toolbar}>
{smomodsLogo}
<div>{getMenuButtons()}</div>
</Toolbar>
)
};
const getDrawerChoices = () => {
return headersData.map(({ label, href }) => {
return (
<Link
{...{
component: RouterLink,
to: href,
color: "inherit",
style: { textDecoration: "none" },
key: label,
}}
>
<MenuItem>{label}</MenuItem>
</Link>
)
})
}
const displayMobile = () => {
const handleDrawerOpen = () =>
setState((prevState) => ({ ...prevState, drawerOpen: true }));
const handleDrawerClose = () =>
setState((prevState) => ({ ...prevState, drawerOpen: false }));
return (
<Toolbar>
<IconButton
{...{
edge: "start",
color: "inherit",
"aria-label": "menu",
"aria-haspopup": "true",
onClick: handleDrawerOpen,
}}
>
<MenuIcon/>
</IconButton>
<Drawer
{...{
anchor: "left",
open: drawerOpen,
onClose: handleDrawerClose,
}}
>
<div className={drawerContainer}>{getDrawerChoices()}</div>
</Drawer>
<div>{smomodsLogo}</div>
</Toolbar>
)
}
const smomodsLogo = (
<Typography variant="h6" component="h1">
<img src={logo} alt="SMOMods" width={224} height={70}/>
</Typography>
)
const getMenuButtons = () => {
return headersData.map(({ label, href }) => {
return (
<Button
{...{
key: label,
color: "inherit",
to: href,
component: RouterLink,
className: menuButton
}}
>
{label}
</Button>
);
});
};
return (
<header>
<AppBar className={header}>{mobileView ? displayMobile() : displayDesktop()}</AppBar>
</header>
);
}
The drawer uses Material-UI in ReactJS. I am really new to React and it's my first time using it. I have added something like BackgroundColor: "#1b1b1b" to the code before but it only changed the background color behind the buttons and not the full drawer!
There is documentation written under the Drawer tab.
https://mui.com/api/drawer/
There is another way to do that is to overwrite the original class by inspecting that element, or create an above your drawer, and change the color as a child.
I forked your example and apply the changes from the question that I suggested you via comments before and here you have your code working with a red background for the Drawer.
Changes I introduced to make it work were all in the Header.js file:
Added new style named paper to the makeStyles invocation at line 17
Changed const { header, menuButton, toolbar, drawerContainer } = useStyles(); by const { paper, header, menuButton, toolbar, drawerContainer } = useStyles();
Added classes={{ paper }} to the Drawer instance
A few extra things you could improve:
You do not need destructuring when you use a component:
<Drawer
classes={{ paper }}
{...{
anchor: "left",
open: drawerOpen,
onClose: handleDrawerClose
}}
>
<div className={drawerContainer}>{getDrawerChoices()}</div>
</Drawer>
Is usually written like this:
<Drawer
classes={{ paper }}
anchor="left"
open={drawerOpen}
onClose={handleDrawerClose}
>
<div className={drawerContainer}>{getDrawerChoices()}</div>
</Drawer>
Instead of:
return (
<header>
<AppBar className={header}>
{mobileView ? displayMobile() : displayDesktop()}
</AppBar>
</header>
);
You should do:
return (
<AppBar className={header}>
{mobileView ? displayMobile() : displayDesktop()}
</AppBar>
);

Reactjs: How to use a callback passed to this child component to update a parent component's state

The child component will add data and the parent component will display the latest data that the child component inserted, my problem is the useState didnt work properly, because the data is successfully saved but i cant see the data inserted in the parent component, need to refresh or load the page to see the latest data.
Parent component
const fetchData = async () => {
const response = await getDepartment('fmDepartments', 'fmDepartmentsId', 'All', 100, 0);
console.log(response)
response.data.map(function(u){
newUsers.push({
sequence:u.sequence,
name: u.name,
datecreated: u.datecreated,
dateupdated: u.dateupdated,
status: u.status,
actions: ([
<div className={classes.root}>
{u.status !== 1 ?(
<Tooltip title={<span style={{fontSize: 15, fontWeight: 600,}}>Deactivate</span>} arrow>
<IconButton
aria-label="Deactivate"
color="primary"
size="small"
className={classes.deactivateButton}
onClick={() => {handleActivate(u.id)}}
>
<HighlightOffIcon />
</IconButton>
</Tooltip>
):(
<Tooltip title={<span style={{fontSize: 15, fontWeight: 600,}}>Activate</span>} arrow>
<IconButton
aria-label="Active"
color="primary"
size="small"
className={classes.activateButton}
onClick={() => {handleDeactivate(u.id)}}
>
<CheckCircleOutlineIcon />
</IconButton>
</Tooltip>
)
}
</div>
])
})
})
setNewUserLists(newUsers)
}
useEffect(() => {
fetchData();
}, [reRender]);
const options = {
filter: true,
filterType: 'checkbox',
selectableRows: 'none',
print: false,
customToolbar: () => {
return (
<CustomToolbar/> //here is the link to the child component
)
},
setFilterChipProps: (colIndex, colName, data) => {
return {
color: 'primary',
variant: 'outlined',
className: 'testClass123',
};
}
};
return (
<>
<MUIDataTable
title={"Department"}
data={newUserLists}
columns={columns}
options={options}
/>
</>
)
child component
class CustomToolbar extends React.Component {
constructor(props) {
super(props)
this.HandleAdd = this.HandleAdd.bind(this);
this.state =false //here
}
HandleAdd = () => {
Swal.fire({
title: 'Add Department',
text: "Input department name below.",
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Save',
html: generateInputForms({
strname: '',
intsequence: ''
}),
preConfirm: () => {
let strname = document.getElementById('strname').value;
let intsequence = document.getElementById('intsequence').value;
if (!strname) {
Swal.showValidationMessage('The Department field is required.')
}
if (!intsequence) {
Swal.showValidationMessage('The Sequence field is required.')
}
return {
strname: document.getElementById('strname').value,
intsequence: document.getElementById('intsequence').value
}
}
}).then((result) => {
if (result.isConfirmed) {
let request = {
strresourcename: "Richard",
strapplicationcode: "SchoolApp",
strmodulename: "Department",
strtablename: "fmDepartments",
strfieldid: "fmDepartmentsId",
strname:document.getElementById('strname').value,
intsequence:document.getElementById('intsequence').value
}
addDepartment(request).then(res =>{
if (res.status == 200){
Swal.fire({
icon: 'success',
title: 'Department',
text: 'New Department has been added successfully.',
}).then(res => {
this.setState(!this.state); //here
})
}else{
Swal.fire({
icon: 'error',
title: 'Oops',
text: 'Something went wrong.',
})
}
})
}
})
}
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Tooltip title={"Add"}>
<Button
variant="contained"
color="primary"
size="small"
style={{
textTransform: 'unset',
outline: 'none',
marginLeft: 20,
backgroundColor: '#00B029',
}}
onClick={this.HandleAdd}
className={classes.button}
startIcon={<AddIcon className={classes.addIcon} style={{color: '#fff',}} />}
>
Add
</Button>
</Tooltip>
</React.Fragment>
);
}
}

Categories