Set active tabpanel mui from router nextjs - javascript

I'm trying to set active tab using router pid
Here is how
function dashboard({ tabId }) {
const classes = useStyles();
const [value, setValue] = React.useState("");
useEffect(() => {
console.log(tabId)
if (tabId) {
setValue(tabId);
}
}, [])
.......
}
Each of my TabPanel have a custom value how is the same I'm trying to pass as router parameter (pid)
The pid is get by getInitialProps
dashboard.getInitialProps = async ({ query }) => {
if (!query.pid) {
return { tabId: 0 }
}
return { tabId: query.pid }
}
So the issue is, the tab is set as active but the content of the tab is not show ... Only the tab is set to active...
Tabs/TabPanel
<Tabs value={value}
onChange={handleChange}
initialSelectedIndex={1}
variant="fullWidth"
aria-label="simple tabs example"
TabIndicatorProps={{
style: {
display:'none',
}
}}
>
<Tab label="ACCUEIL" value="accueil" classes={{ root: classes.rootTab, selected: classes.selectedTab }} {...a11yProps(0)} />
<Tab label="GÉRER SA GAMME" value="ma-gamme" classes={{ root: classes.rootTab, selected: classes.selectedTab }} {...a11yProps(1)} />
.........
</Tabs>
</AppBar >
<TabPanel value="accueil" index={0}>
</TabPanel>
<TabPanel value="ma-gamme" index={1}>
</TabPanel>
......
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Container>
<Box p={3}>
{children}
</Box>
</Container>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
};
}
Any help would be appreciate :)
Fixed by juliomalves
I was using string value instead of value={index}

Fixed by juliomalves
I was using string value instead of value={index}

Related

How to send/receive props to BasicLayout (#devexpress/dx-react-scheduler)

I'm from Angular and new to React. Im doing well but here is a problem I'm stuck at. As you can see I have BasicLayout and AppointmentForm, both are in one file. BasicLayout is being used inside AppointmentForm but not like an element i.e <BasicLayout/> so I'm not able to understand how to pass props or its even possible now. I want to trigger commitChanges(inside AppointmentForm) function when onSubmit(inside Basic Layout) function is triggered. How can I pass props between these components?
const BasicLayout = (props) => {
const formik = useFormik({
initialValues: {
title: '',
agenda: '',
description: '',
participants: [],
host: user?.id,
guest: '',
location: '',
},
validationSchema,
onSubmit: async (values) => {
values.startDate = props.appointmentData.startDate;
values.endDate = props.appointmentData.endDate;
values.guest = values.guest?._id;
createAppointment(values);
console.log(values);
},
});
return (
<Container>
<Typography sx={{ fontSize: 24, fontWeight: 'bold' }} color="text.primary" gutterBottom>
Create Appointment
</Typography>
<Box sx={{ flexGrow: 1 }}>
<FormikProvider value={formik}>
<Form autoComplete="off" onSubmit={handleSubmit}>
<Grid container spacing={2}>
<Grid item xs={6} md={6}>
<TextField
label="Title"
color="secondary"
id="title"
type="text"
key="title"
value={formik.values.title}
onChange={formik.handleChange}
{...getFieldProps('title')}
error={Boolean(touched.title && errors.title)}
helperText={touched.title && errors.title}
fullWidth
/>
</Grid>
<Grid item container xs={12} md={12} direction="row" justifyContent="center" alignItems="center">
<LoadingButton size="medium" type="submit" variant="contained" loading={isSubmitting}>
Create
</LoadingButton>
</Grid>
</Grid>
</Form>
</FormikProvider>
</Box>
<ToastContainer />
</Container>
);
};
const AppointmentsDashboard = (props) => {
const commitChanges = ({ added, changed, deleted }) => {
console.log(props);
console.log({ added, changed, deleted });
if (added) {
if (!isValidate) {
notify('Please fill all required fields', 'error');
return;
}
const startingAddedId = data.length > 0 ? data[data.length - 1].id + 1 : 0;
setData([...data, { id: startingAddedId, ...added }]);
}
if (changed) {
setData(
data.map((appointment) =>
changed[appointment.id] ? { ...appointment, ...changed[appointment.id] } : appointment
)
);
}
if (deleted !== undefined) {
setData(data.filter((appointment) => appointment.id !== deleted));
}
return data;
};
return (
<>
<Paper>
<Scheduler data={data} height={660}>
<ViewState currentDate={currentDate} />
<EditingState
onCommitChanges={commitChanges}
addedAppointment={addedAppointment}
onAddedAppointmentChange={changeAddedAppointment}
appointmentChanges={appointmentChanges}
onAppointmentChangesChange={changeAppointmentChanges}
editingAppointment={editingAppointment}
onEditingAppointmentChange={changeEditingAppointment}
onAppointmentFormClosing={() => {
console.log('asdasd');
}}
allowAdding={true}
/>
<WeekView startDayHour={9} endDayHour={17} />
<AllDayPanel />
<EditRecurrenceMenu />
<ConfirmationDialog />
<Appointments />
<AppointmentTooltip showOpenButton showDeleteButton />
<AppointmentForm basicLayoutComponent={BasicLayout} />
</Scheduler>
</Paper>
</>
);
};
export default AppointmentsDashboard;

Is rendering the Autocomplete options list with column headers possible?

I would like to know if it is possible to customise the above example so that the list would have column headers such as Title and duration. I have tried to see if I could get it to work using a custom ListBox, but no such luck. Below is a snippet of my own code:
const PopperMy = function (props: PopperProps) {
return <Popper {...props} style={{ width: 500 }} placement='bottom-start' />;
};
return (
<Autocomplete
filterOptions={(x) => x}
getOptionLabel={(option: Record<string, unknown>) => `${option.order}, ${option.name}, ${option.email}, ${option.phone}, ${option.location}`}
renderOption={(props, option: any) => {
return (
<li {...props} key={option.ID} >
Order: {option.order}, Name: {option.name}, Email: {option.email}, Phone: {option.phone}, Location: {option.location}, Status: {option.status}
</li>
);
}}
options={results}
value={selectedValue}
clearOnBlur={false}
freeSolo
PopperComponent={PopperMy}
disableClearable={true}
includeInputInList
onChange={(ev, newValue) => {
setSelectedValue(newValue);
}}
onInputChange={(ev, newInputValue) => {
setInputValue(newInputValue);
}}
renderInput={(params) => (
<TextField {...params} />
)} /> )
this is achievable by customizing the popper component. In your case, something like `
const PopperMy = function (props) {
const { children, ...rest } = props;
return (
<Popper {...rest} placement="bottom-start">
<Box display="flex" justifyContent="space-between" px="16px">
<Typography variant="h6">Title</Typography>
<Typography variant="h6">Year</Typography>
........... rest of the titles
</Box>
{props.children}
</Popper>
);
};
`
would work. Here is a working example i have created - https://codesandbox.io/s/heuristic-golick-4sv24u?file=/src/App.js:252-614

React - Close MUI drawer from nested menu

I'm using this excellent example (Nested sidebar menu with material ui and Reactjs) to build a dynamic nested menu for my application. On top of that I'm trying to go one step further and put it into a Material UI appbar/temporary drawer. What I'd like to achieve is closing the drawer when the user clicks on one of the lowest level item (SingleLevel) however I'm having a tough time passing the toggleDrawer function down to the menu. When I handle the click at SingleLevel I consistently get a 'toggle is not a function' error.
I'm relatively new to this so I'm sure it's something easy and obvious. Many thanks for any answers/comments.
EDIT: Here's a sandbox link
https://codesandbox.io/s/temporarydrawer-material-demo-forked-v11ur
Code is as follows:
Appbar.js
export default function AppBar(props) {
const [drawerstate, setDrawerstate] = React.useState(false);
const toggleDrawer = (state, isopen) => (event) => {
if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) {
return;
}
setDrawerstate({ ...state, left: isopen });
};
return (
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static" color="secondary">
<Toolbar>
<IconButton
size="large"
edge="start"
color="primary"
aria-label="menu"
onClick={toggleDrawer('left', true)}
>
<MenuIcon />
</IconButton>
<img src={logo} alt="logo" />
</Toolbar>
<Drawer
anchor='left'
open={drawerstate['left']}
onClose={toggleDrawer('left', false)}
>
<Box>
<AppMenu toggleDrawer={toggleDrawer} />
</Box>
</Drawer>
</AppBar>
</Box >
)
}
Menu.js
export default function AppMenu(props) {
return MenuItemsJSON.map((item, key) => <MenuItem key={key} item={item} toggleDrawer={props.toggleDrawer} />);
}
const MenuItem = ({ item, toggleDrawer }) => {
const MenuComponent = hasChildren(item) ? MultiLevel : SingleLevel;
return <MenuComponent item={item} toggleDrawer={toggleDrawer} />;
};
const SingleLevel = ({ item, toggleDrawer }) => {
const [toggle, setToggle] = React.useState(toggleDrawer);
return (
<ListItem button onClick={() => { toggle('left', false) }}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.title} />
</ListItem>
);
};
const MultiLevel = ({ item }) => {
const { items: children } = item;
const [open, setOpen] = useState(false);
const handleClick = () => {
setOpen((prev) => !prev);
};
return (
<React.Fragment>
<ListItem button onClick={handleClick}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.title} secondary={item.description} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{children.map((child, key) => (
<MenuItem key={key} item={child} />
))}
</List>
</Collapse>
</React.Fragment>
);
};
You shouldn't call a react hook inside of any function that is not a react component. Please see React Rules of Hooks
What you could do instead is pass setToggle directly into the Drawer component as a prop and do something like this for it's onClick attribute:
onClick={() => setToggle(<value>)}

How to use the info received in a class into a function React Axios

Im new to react and I want to receive a list of items from an API using Axios in a react class, and then I want to use this info in a react function:
export class JobGetter extends Component {
state = {
Jobs: [],
};
componentDidMount() {
axios.get('/api/jobs/list-jobs', { headers: headers }).then(res => {
this.setState({
Jobs: res.data.map(Jobs => ({
value: Jobs.id,
title: Jobs.title,
companyName: Jobs.company_name,
InternalCode: Jobs.internal_code,
department: Jobs.department,
location: Jobs.location,
tags: Jobs.tags,
benefits: Jobs.benefits,
description: Jobs.description,
requirements: Jobs.requirements,
})),
}, () => {
console.log(this.state.Jobs);
});
});
}
render () {
return (
Jobs
)
}
}
export default function Jobs () {
const classes = useStyles();
return (
<div className='mainBox'>
<div className={classes.root}>
<ExpansionPanel style={{ backgroundColor: 'white' }}>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-controls='panel1a-content'
id='panel1a-header'
style={{ backgroundColor: '#11ed7f' }}
>
<Typography className={classes.heading}>Job Opportunity</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Container className='jobContainer'>
<Typography className={classes.TextHeaders}>
<Row>
<Col>Title:{Jobs.title} </Col>
<Col>Company Name:{Jobs.companyName} </Col>
<Col>Internal Code:{Jobs.InternalCode} </Col>
</Row>
.....
but my GET request doesn't function and I don't receive any info/show any info. what is the correct way to implement this?
With below changes, you should be able to get the data
JobGetter
render() {
return <Jobs jobs={this.state.Jobs} />;
}
Jobs
export default function Jobs ({ jobs }) {
OR
export default function Jobs (props) {
const { jobs } = props;
JobGetter
import Jobs from './Jobs'
export class JobGetter extends Component {
state = {
jobs: [],
};
componentDidMount() {
axios.get('/api/jobs/list-jobs', { headers: headers }).then(res => {
this.setState({
jobs: res.data.map(job => ({
value: job.id,
title: job.title,
companyName: job.company_name,
InternalCode: job.internal_code,
department: job.department,
location: job.location,
tags: job.tags,
benefits: job.benefits,
description: job.description,
requirements: job.requirements,
})),
}, () => {
console.log(this.state.jobs);
});
});
}
render () {
return (
<Jobs jobs={this.state.jobs} />
)
}
}
Jobs
export default function Jobs ({jobs}) {
const classes = useStyles();
return (
<div className='mainBox'>
<div className={classes.root}>
<ExpansionPanel style={{ backgroundColor: 'white' }}>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-controls='panel1a-content'
id='panel1a-header'
style={{ backgroundColor: '#11ed7f' }}
>
<Typography className={classes.heading}>Job Opportunity</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Container className='jobContainer'>
<Typography className={classes.TextHeaders}>
{jobs.map(job => (
<Row key={`job.value`}>
<Col>Title:{Jobs.title} </Col>
<Col>Company Name:{job.companyName} </Col>
<Col>Internal Code:{job.InternalCode} </Col>
</Row>)
)}
</Typography>
</Container>
</ExpansionPanelDetails>
</div>
</div>
Node: you are mixing functional components with classes.

How to manage multiple navigation items states?

I'm trying to implement a horizontal menu with antd components.
When clicking the nav items the submenu is not showing correctly.
Codesandbox demo.
const MenuList = [
{
name: "Navigation two - Submenu",
subMenuRoutes: [
{
name: "A- item1",
url: "/item1Url1"
},
{
name: "A - item2",
url: "/item1Url2"
}
]
},
{
name: "Navigation Three - Submenu",
subMenuRoutes: [
{
name: "B- item1",
url: "/item1Url1"
},
{
name: "B - item2",
url: "/item1Url2"
}
]
}
];
function TextAreaManager() {
const [showMenu, setShowMenu] = useState(false);
return (
<Tabs onTabClick={() => setShowMenu(prev => !prev)}>
{MenuList.map(item => {
return (
<TabPane
tab={
<>
<Icon type="setting" />
{item.name}
<Icon
type={showMenu ? "up" : "down"}
style={{ marginLeft: "10px" }}
/>
</>
}
>
{showMenu && (
<Menu>
{item.subMenuRoutes.map(childItem => {
return (
<Menu.Item key={childItem.url}>{childItem.name}</Menu.Item>
);
})}
</Menu>
)}
</TabPane>
);
})}
</Tabs>
);
There are a few issues that need to be handled:
Assign unique key for every array item in order to render components correctly.
menuList.map(item => <TabPane key={item.name}></TabPane>);
You need to manage every menu's state in order to show menus correctly with the corresponding icon showMenuManager[item.name]:
<Tabs
onTabClick={e =>
setShowMenuManager(prev => {
const newState = { ...initMenuState, [e]: !prev[e] };
console.log(newState);
return newState;
})
}
/>;
const initMenuState = {
"Navigation two - Submenu": false,
"Navigation Three - Submenu": false
};
function TopMenuManager() {
const [showMenuManager, setShowMenuManager] = useState(initMenuState);
return (
<Tabs ... >
{menuList.map(item => (
<TabPane
key={item.name}
tab={
<>
...
<Icon
type={showMenuManager[item.name] ? "up" : "down"}
/>
</>
}
>
{showMenuManager[item.name] && ...}
</TabPane>
))}
</Tabs>
);
}
Check the final example and forked sandbox:

Categories

Resources