Next js: Error: Objects are not valid as a React child (found: Error: Response not successful: Received status code 401) - reactjs

This app shows Github issues with graphql API.
I didn't change anything after finishing the app but I got this error.
I used Next js, Typescript, Material UI, Tailwind css and GraphQL for this project.
Index Component
import React, { useState } from "react"
import { Typography, Container, makeStyles } from "#material-ui/core"
import SearchBar from "../components/SearchBar/SearchBar"
import RepositoryList from "../components/RepositoryList/RepositoryList"
import Head from "next/head"
const useStyles = makeStyles({
title: {
marginTop: "1rem",
marginBottom: "1rem",
textAlign: "center",
},
})
const App = () => {
const classes = useStyles()
const [searchTerm, setSearchTerm] = useState<string>("")
return (
<>
<Head>
<title>GraphQL Github Client</title>
</Head>
<Container maxWidth={"sm"}>
<div className="mt-10 mb-5">
<Typography variant={"h3"} className={classes.title}>
GraphQL Github Client
</Typography>
</div>
<SearchBar
className="mb-10"
value={searchTerm}
onChange={setSearchTerm}
/>
<RepositoryList searchTerm={searchTerm} />
</Container>
</>
)
}
export default App
RepositoryList Component
import React, { useEffect, useState } from "react"
import { Typography, CircularProgress, makeStyles } from "#material-ui/core"
import { useQuery } from "#apollo/react-hooks"
import { SEARCH_FOR_REPOS } from "../../Queries/queries"
import Repository from "../Repository/Repository"
interface RepositoryListProps {
searchTerm?: string
}
const useStyles = makeStyles({
note: {
marginTop: "1rem",
textAlign: "center",
},
spinnerContainer: {
display: "flex",
justifyContent: "space-around",
marginTop: "1rem",
},
})
const RepositoryList: React.FC<RepositoryListProps> = ({ searchTerm }) => {
const classes = useStyles()
const [expandedRepo, setExpandedRepo] = useState(null)
const { data, loading, error } = useQuery(SEARCH_FOR_REPOS, {
variables: { search_term: searchTerm },
})
useEffect(() => {
setExpandedRepo(null)
}, [data])
if (loading) {
return (
<div className={classes.spinnerContainer}>
<CircularProgress />
</div>
)
}
if (error) {
return (
<Typography
variant={"overline"}
className={classes.note}
component={"div"}
color={"error"}
>
{error}
</Typography>
)
}
if (!data.search.repositoryCount) {
return (
<Typography
variant={"overline"}
className={classes.note}
component={"div"}
>
There are no such repositories!
</Typography>
)
}
return (
<div>
{data.search.edges.map(
(
repo: { edges: { id: number } },
i: string | number | ((prevState: null) => null) | null | any
) => (
<>
<Repository
repo={repo}
expanded={expandedRepo === i}
onToggled={() => setExpandedRepo(i)}
key={repo.edges.id}
/>
</>
)
)}
</div>
)
}
export default RepositoryList
Repository Component
import React from "react"
import {
ExpansionPanel,
ExpansionPanelSummary,
ExpansionPanelDetails,
Typography,
Chip,
makeStyles,
} from "#material-ui/core"
import StarIcon from "#material-ui/icons/Star"
import PeopleIcon from "#material-ui/icons/People"
import IssueList from "../IssueList/IssueList"
const useStyles = makeStyles({
root: {
marginTop: "1rem",
},
summaryContainer: {
flexDirection: "column",
},
summaryHeader: {
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
marginBottom: "1rem",
},
chip: {
marginLeft: "0.5rem",
},
})
interface RepositoryProps {
repo: any
expanded: boolean
onToggled: any
}
const Repository: React.FC<RepositoryProps> = ({
repo,
expanded,
onToggled,
}) => {
const {
node: {
name,
descriptionHTML,
owner: { login },
stargazers: { totalCount: totalStarCount },
},
} = repo
const classes = useStyles()
return (
<ExpansionPanel
expanded={expanded}
onChange={onToggled}
className={classes.root}
>
<ExpansionPanelSummary classes={{ content: classes.summaryContainer }}>
<div className={classes.summaryHeader}>
<Typography variant={"h6"}>{name}</Typography>
<div>
<Chip
label={`by ${login}`}
avatar={<PeopleIcon />}
className={classes.chip}
/>
<Chip
label={totalStarCount}
avatar={<StarIcon />}
className={classes.chip}
/>
</div>
</div>
<Typography
variant={"caption"}
dangerouslySetInnerHTML={{ __html: descriptionHTML }}
component={"div"}
/>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
{expanded && <IssueList repoName={name} repoOwner={login} />}
</ExpansionPanelDetails>
</ExpansionPanel>
)
}
export default Repository
These are my components.
What should I do for fixing this problem?

It looks like the issue is in this spot where you do {error}. I would double check what error actually is but it looks like its an object and not a string like you are using it
<Typography
variant={"overline"}
className={classes.note}
component={"div"}
color={"error"}
>
{error}
</Typography>

Related

Refine dashboard showing error---Error: SyntaxError: Unexpected token, expected ";" (7:22)

image showing the error
I tried to implement the google login in my react app using refine. I was trying to make a react app using refine and other packages.
I was following a course on youtube, i almost followed the youtuber till this step but my code was giving error while his wasn't.
But this error popped up.
The below is my code.
import { useEffect, useRef } from "react";
import { useLogin } from "#pankod/refine-core";
import { Container, Box } from "#pankod/refine-mui";
import { yariga } from "../assets";
import { CredentialResponse } from "../interfaces/google";
export const Login: React.FC = () => {
const { mutate: login } = useLogin<CredentialResponse>();
const GoogleButton = (): JSX.Element => {
const divRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (typeof window === "undefined" || !window.google || !divRef.current) {
return;
}
try {
window.google.accounts.id.initialize({
ux_mode: "popup",
client_id: process.env.REACT_APP_GOOGLE_CLIENT_ID,
callback: async (res: CredentialResponse) => {
if (res.credential) {
login(res);
}
},
});
window.google.accounts.id.renderButton(divRef.current, {
theme: "filled_blue",
size: "medium",
type: "standard",
});
} catch (error) {
console.log(error);
}
}, []); // you can also add your client id as dependency here
return <div ref={divRef} />;
};
return (
<Box
component="div"
sx={{ backgroundColor: "#FCFCFC" }}
>
<Container
component="main"
maxWidth="xs"
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
height: "100vh",
}}
>
<Box
sx={{
display: "flex",
justifyContent: "center",
flexDirection: "column",
alignItems: "center",
}}
>
<div>
<img src={yariga} alt="Yariga Logo" />
</div>
<Box mt={4}>
<GoogleButton />
</Box>
</Box>
</Container>
</Box>
);
};

usecontext without child component?

I'm wanting to pass a state from my WeatherComponent through to my UserForm component and ideally would like to do this without making the UserForm a child component. At the moment I have the UserForm as a child component and that component is working fine when I render it because it's getting the weather state from the WeatherComponent. But now when I want to render my WeatherComponent it renders the UserComponent as well.
Is there another way I could use useContext or a method that doesn't rely on making a child component?
WeatherComponent:
import axios from 'axios';
import { useEffect, useState, createContext } from 'react';
import { Weather } from '../types';
import { MdWbSunny } from 'react-icons/md';
import { IoIosPartlySunny } from 'react-icons/io';
import { BsFillCloudSnowFill } from 'react-icons/bs';
import { Title, Text, Container } from '#mantine/core';
import UserForm from './UserForm';
export const WeatherContext = createContext<any>(null);
const WeatherComponent = () => {
const [weather, setWeather] = useState<Weather | null>();
const fetchWeatherData = async () => {
const response = await axios.get('http://mock-api-call/weather/get-weather');
setWeather(response.data.result.weather);
};
useEffect(() => {
fetchWeatherData();
}, []);
return (
<Container>
<WeatherContext.Provider value={weather?.forcast}>
<UserForm />
</WeatherContext.Provider>
<Title order={2}>
{weather?.forcast === 'Sunny' ? (
<MdWbSunny data-testid="sunny" />
) : weather?.forcast === 'Snowing' ? (
<BsFillCloudSnowFill data-testid="snowing" />
) : (
<IoIosPartlySunny data-testid="overcast" />
)}
</Title>
<Text size="xl" data-testid="forcast">
{weather?.forcast}
</Text>
<Text size="lg" data-testid="temp">
Temp: {`${weather?.min} to ${weather?.max}`}
</Text>
<Text size="md" data-testid="description">
{weather?.description}
</Text>
</Container>
);
};
export default WeatherComponent;
UserForm:
import React, { useContext, useState } from 'react';
import { Container, Title, TextInput, Button, Group, Header } from '#mantine/core';
import { useStateWithLocalStorage } from './UseStateWithLocalStorage';
import { WeatherContext } from './WeatherComponent';
import { MdWbSunny } from 'react-icons/md';
import { BsFillCloudSnowFill } from 'react-icons/bs';
import { IoIosPartlySunny } from 'react-icons/io';
const UserForm = () => {
const [inputValue, setInputValue] = useStateWithLocalStorage('', 'form');
const [show, setShow] = useState(true);
const weatherIcon = useContext(WeatherContext);
function handleChange(event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) {
setInputValue(() => ({
[event.target.name]: event.target.value,
}));
}
return (
<Header height={56} mb={120}>
<Container
style={{
display: 'flex',
flexDirection: 'row',
backgroundColor: 'gray',
justifyContent: 'space-between',
color: 'white',
alignItems: 'center',
padding: '10px',
fontSize: '25px',
fontWeight: 'bold',
boxShadow: '0 3px 6px 0 #555',
}}
>
<Group>
<Title order={2}>Welcome </Title>
{show && (
<TextInput
type="text"
name="name"
id="name"
placeholder="enter your name"
onChange={handleChange}
value={inputValue.name}
/>
)}
{show && <Button onClick={() => setShow((prev) => !prev)}>SAVE</Button>}
<Title order={2}>{inputValue.name ? inputValue.name : ''}</Title>
</Group>
<Group style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Title order={2}>
{weatherIcon === 'Sunny' ? (
<MdWbSunny data-testid="sunny" />
) : weatherIcon === 'Snowing' ? (
<BsFillCloudSnowFill data-testid="snowing" />
) : (
<IoIosPartlySunny data-testid="overcast" />
)}
</Title>
</Group>
</Container>
</Header>
);
};
export default UserForm;

I want to navigate to home page upon successfull authentication

I am working on a next.js theme. I want to navigate to the "dashboards/analytics" page upon successfull authentication. we are using JWT based authentication. Authentication is done. but i could not navigate to the dashboards page.I really could not understand what is wrong in this code. Also i am getting a "Password is required error" even after passing a value. but it is not effecting the login function(i was able to login though, with the same password value). i tried commenting out the "yup resolver" code. but it didnt show any error when i clicked login button without a password(but login was not successfull). Kindly someone help me to fix these issues.
AuthContext.js file is as shown below
// ** React Imports
import { createContext, useEffect, useState } from 'react'
// ** Next Import
import {useRouter} from 'next/router'
// ** Axios
import axios from 'axios'
// ** Config
import authConfig from 'src/configs/auth'
// ** Defaults
const defaultProvider={
user: null,
loading: true,
setUser: () => null,
setLoading: () => Boolean,
isInitialized: false,
login: (token) => {},
logout: () => Promise.resolve(),
setIsInitialized: () => Boolean,
register: () => Promise.resolve(),
token:'',
};
const AuthContext = createContext(defaultProvider)
const AuthProvider = ({ children }) => {
// ** States
const [user, setUser] = useState(defaultProvider.user)
const [loading, setLoading] = useState(defaultProvider.loading)
const [isInitialized, setIsInitialized] = useState(defaultProvider.isInitialized)
const [token,setToken]=useState(defaultProvider.token)
// ** Hooks
const router = useRouter()
useEffect(() => {
const initAuth = async () => {
setIsInitialized(true)
const storedToken = window.localStorage.getItem(authConfig.storageTokenKeyName)
if (storedToken) {
setLoading(true)
await axios
.get(authConfig.meEndpoint, {
headers: {
Authorization: storedToken
}
})
.then(async response => {
setLoading(false)
setUser({ ...response.data.userData })
})
} else {
setLoading(false)
}
}
initAuth()
}, [])
const handleLogin=(token)=>{
setToken(token);
router.push('/dashboards/analytics');
}
const handleLogout = () => {
setUser(null)
setIsInitialized(false)
window.localStorage.removeItem('userData')
window.localStorage.removeItem(authConfig.storageTokenKeyName)
router.push('/login')
}
const handleRegister = (params, errorCallback) => {
axios
.post(authConfig.registerEndpoint, params)
.then(res => {
if (res.data.error) {
if (errorCallback) errorCallback(res.data.error)
} else {
handleLogin({ email: params.email, password: params.password })
}
})
.catch(err => (errorCallback ? errorCallback(err) : null))
}
const values = {
user,
loading,
setUser,
setLoading,
isInitialized,
setIsInitialized,
login: handleLogin,
logout: handleLogout,
register: handleRegister,
token
}
return <AuthContext.Provider value={values}>{children}</AuthContext.Provider>
}
export { AuthContext, AuthProvider }
Login/index.js file is as shown below,
// ** React Imports
import { useState, useContext } from 'react'
import {useRouter} from 'next/router'
// ** Next Imports
import Link from 'next/link'
import axios from 'axios'
// ** MUI Components
import Button from '#mui/material/Button'
import Divider from '#mui/material/Divider'
import Checkbox from '#mui/material/Checkbox'
import TextField from '#mui/material/TextField'
import InputLabel from '#mui/material/InputLabel'
import IconButton from '#mui/material/IconButton'
import Box from '#mui/material/Box'
import FormControl from '#mui/material/FormControl'
import useMediaQuery from '#mui/material/useMediaQuery'
import OutlinedInput from '#mui/material/OutlinedInput'
import { styled, useTheme } from '#mui/material/styles'
import FormHelperText from '#mui/material/FormHelperText'
import InputAdornment from '#mui/material/InputAdornment'
import Typography from '#mui/material/Typography'
import MuiFormControlLabel from '#mui/material/FormControlLabel'
// ** Icons Imports
import Google from 'mdi-material-ui/Google'
import Github from 'mdi-material-ui/Github'
import Twitter from 'mdi-material-ui/Twitter'
import Facebook from 'mdi-material-ui/Facebook'
import EyeOutline from 'mdi-material-ui/EyeOutline'
import EyeOffOutline from 'mdi-material-ui/EyeOffOutline'
// ** Third Party Imports
import * as yup from 'yup'
import { useForm, Controller } from 'react-hook-form'
import { yupResolver } from '#hookform/resolvers/yup'
// ** Hooks
import { useAuth } from 'src/hooks/useAuth'
import useBgColor from 'src/#core/hooks/useBgColor'
import { useSettings } from 'src/#core/hooks/useSettings'
// ** Configs
import themeConfig from 'src/configs/themeConfig'
// ** Layout Import
import BlankLayout from 'src/#core/layouts/BlankLayout'
// ** Demo Imports
import FooterIllustrationsV2 from 'src/views/pages/auth/FooterIllustrationsV2'
import { AuthContext } from 'src/context/AuthContext'
// ** Styled Components
const LoginIllustrationWrapper = styled(Box)(({ theme }) => ({
padding: theme.spacing(20),
paddingRight: '0 !important',
[theme.breakpoints.down('lg')]: {
padding: theme.spacing(10)
}
}))
const LoginIllustration = styled('img')(({ theme }) => ({
maxWidth: '48rem',
[theme.breakpoints.down('lg')]: {
maxWidth: '35rem'
}
}))
const RightWrapper = styled(Box)(({ theme }) => ({
width: '100%',
[theme.breakpoints.up('md')]: {
maxWidth: 450
}
}))
const BoxWrapper = styled(Box)(({ theme }) => ({
[theme.breakpoints.down('xl')]: {
width: '100%'
},
[theme.breakpoints.down('md')]: {
maxWidth: 400
}
}))
const TypographyStyled = styled(Typography)(({ theme }) => ({
fontWeight: 600,
marginBottom: theme.spacing(1.5),
[theme.breakpoints.down('md')]: { marginTop: theme.spacing(8) }
}))
const LinkStyled = styled('a')(({ theme }) => ({
fontSize: '0.875rem',
textDecoration: 'none',
color: theme.palette.primary.main
}))
const FormControlLabel = styled(MuiFormControlLabel)(({ theme }) => ({
'& .MuiFormControlLabel-label': {
fontSize: '0.875rem',
color: theme.palette.text.secondary
}
}))
const schema = yup.object().shape({
username: yup.string().required(),
password: yup.string().min(5 ).required()
})
const LoginPage = () => {
const [showPassword, setShowPassword] = useState(false)
const [username,setUsername]=useState('');
const [password,setPassword]=useState('');
//const [errMsg,setErrMsg]=useState('');
// ** Hooks
const auth = useContext(AuthContext);
const theme = useTheme()
const router=useRouter();
const bgClasses = useBgColor()
const {
settings: { skin }
} = useSettings()
const {
control,
setError,
//handleSubmit,
formState: { errors }
} = useForm({
//defaultValues,
mode: 'onBlur',
resolver: yupResolver(schema)
})
// ** Vars
const hidden = useMediaQuery(theme.breakpoints.down('md'))
const handleSubmit=(e)=>{
e.preventDefault();
fetch(
'url',
{
method:'POST',
body:JSON.stringify({
username:username,
password:password,
}),
headers: {
'Content-Type':'application/json',
'X-Correlation-ID':'123456',
'Source-ID':'abc123',
}
}).then(res =>{
if(res.ok){
return res.json();
}
else{
return res.json().then(data=> {
let errorMessage="Authentication Failed";
throw new Error(errorMessage);
});
}
}).then(data=>{
auth.login(data.response.accessToken);
}).catch(err=>{
alert(err.message);
});
}
return (
<Box className='content-right'>
{!hidden ? (
<Box sx={{ flex: 1, display: 'flex', position: 'relative', alignItems: 'center', justifyContent: 'center' }}>
<LoginIllustrationWrapper>
<LoginIllustration
alt='login-illustration'
src={`/images/pages/auth-v2-login-illustration-${theme.palette.mode}.png`}
/>
</LoginIllustrationWrapper>
<FooterIllustrationsV2 />
</Box>
) : null}
<RightWrapper sx={skin === 'bordered' && !hidden ? { borderLeft: `1px solid ${theme.palette.divider}` } : {}}>
<Box
sx={{
p: 12,
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'background.paper'
}}
>
<BoxWrapper>
<Box
sx={{
top: 30,
left: 40,
display: 'flex',
position: 'absolute',
alignItems: 'center',
justifyContent: 'center'
}}
>
<Typography
variant='h6'
sx={{
ml: 3,
lineHeight: 1,
fontWeight: 600,
textTransform: 'uppercase',
fontSize: '1.5rem !important'
}}
>
{themeConfig.templateName}
</Typography>
</Box>
<Box sx={{ mb: 6 }}>
<TypographyStyled variant='h5'>Welcome to {themeConfig.templateName}! 👋🏻</TypographyStyled>
<Typography variant='body2'>Please sign-in to your account and start the adventure</Typography>
</Box>
<form noValidate autoComplete='off' onSubmit={handleSubmit}>
<FormControl fullWidth sx={{ mb: 4 }}>
<Controller
name='Username'
control={control}
rules={{ required: true }}
render={({ field: { value, onChange, onBlur } }) => (
<TextField
autoFocus
label='Username'
value={value}
onBlur={onBlur}
//onChange={onChange}
onChange={(e)=> setUsername(e.target.value)}
error={Boolean(errors.user)}
// placeholder='admin#materio.com'
/>
)}
/>
{errors.user && <FormHelperText sx={{ color: 'error.main' }}>{errors.user.message}</FormHelperText>}
</FormControl>
<FormControl fullWidth>
<InputLabel htmlFor='auth-login-v2-password' error={Boolean(errors.password)}>
Password
</InputLabel>
<Controller
name='password'
control={control}
rules={{ required: true }}
render={({ field: { value,onChange, onBlur } }) => (
<OutlinedInput
value={value}
onBlur={onBlur}
label='Password'
//onChange={onChange}
onChange={(e)=> setPassword(e.target.value)}
id='auth-login-v2-password'
error={Boolean(errors.password)}
type={showPassword ? 'text' : 'password'}
endAdornment={
<InputAdornment position='end'>
<IconButton
edge='end'
onMouseDown={e => e.preventDefault()}
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? <EyeOutline /> : <EyeOffOutline />}
</IconButton>
</InputAdornment>
}
/>
)}
/>
{errors.password && (
<FormHelperText sx={{ color: 'error.main' }} id=''>
{errors.password.message}
</FormHelperText>
)}
</FormControl>
<Box
sx={{ mb: 4, display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'space-between' }}
>
<FormControlLabel control={<Checkbox />} label='Remember Me' />
<Link passHref href='/forgot-password'>
<LinkStyled>Forgot Password?</LinkStyled>
</Link>
</Box>
<Button fullWidth size='large' type='submit' variant='contained' sx={{ marginBottom: 7 }}>
Login
</Button>
<Box sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'center' }}>
<Typography variant='body2' sx={{ marginRight: 2 }}>
New on our platform?
</Typography>
<Typography variant='body2'>
<Link passHref href='/register'>
<LinkStyled>Create an account</LinkStyled>
</Link>
</Typography>
</Box>
<Divider sx={{ my: 5 }}>or</Divider>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Facebook sx={{ color: '#497ce2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Twitter sx={{ color: '#1da1f2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Github
sx={{ color: theme => (theme.palette.mode === 'light' ? '#272727' : theme.palette.grey[300]) }}
/>
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Google sx={{ color: '#db4437' }} />
</IconButton>
</Link>
</Box>
</form>
</BoxWrapper>
</Box>
</RightWrapper>
</Box>
)
}
LoginPage.getLayout = page => <BlankLayout>{page}</BlankLayout>
LoginPage.guestGuard = true
export default LoginPage

Dynamic URL in React

I'm working on a React project with Redux and I'm consuming a Rest API, I need to implement a functionality where when I select a project from a list and I need to load the project ID in the URL and direct to another screen where a sidebar with the options is loaded. navigation of this project.
Example: Layout
I managed to load the project's Id in the URL and retrieve this ID in the project's home screen, the problem is to store the project's Id and set this ID in the next selected URLs, for example:
path: '/project/:id/companies'
path: '/project/:id/currencies'
path: '/project/:id/settings'
List of projects:
Capture the project id and arrow the url:
href={`#/project/${row.id}/main`}
Routes:
path: '/project/:id/main',
exact: true,
name: 'projectMain',
component: RequireAuth(ProjectMain),
Retrieve ID in main
import { useParams } from 'react-router-dom';
...
const { id } = useParams();
The problem is in the sidebar, where I load a list of items with the path, I'm not able to pass the project id in this list.
Complementando a pergunta
In Sidebar I'm using useHistory(), the problem is that the path comes static by 'props' through importing a file into my template, as you can see below:
Template
import React from 'react';
import { Grid, makeStyles } from '#material-ui/core';
import {
AppContent,
AppHeader,
SidebarApp,
} from '../components/index';
import itemsProject from '../components/itemsSidebar/itemsProject';
const useStyles = makeStyles(theme => ({
appContent: {
paddingLeft: 240,
width: '100%',
backgroundColor: theme.palette.background.paper,
},
}));
const ProjectLayout = () => {
const classes = useStyles();
return (
<div className={classes.appContent}>
<AppHeader />
<Grid container direction="row">
<SidebarApp items={itemsProject} />
<AppContent />
</Grid>
</div>
);
};
export default ProjectLayout;
Sidebar:
/* eslint-disable react/jsx-no-duplicate-props */
import React from 'react';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import Divider from '#material-ui/core/Divider';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import ExpandLessIcon from '#material-ui/icons/ExpandLess';
import Collapse from '#material-ui/core/Collapse';
import {
alpha,
Box,
Card,
ListSubheader,
makeStyles,
Typography,
} from '#material-ui/core';
import { useHistory, useLocation, useParams } from 'react-router-dom';
import translate from '../providers/i18n/translate';
const useStyles = makeStyles(theme => ({
sidebar: {
background: theme.palette.background.dark,
width: 240,
height: '100vh',
border: '1px solid rgba(0, 0, 0, 0.1)',
display: 'flex',
flexDirection: 'column',
position: 'absolute',
paddingTop: 64,
top: 0,
left: 0,
},
sidebarItem: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
},
sidebarItemContent: {
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
width: '100%',
},
sidebarItemIcon: {
marginRight: 6,
},
sidebarItemText: {
width: '100%',
},
sidebarItemExpandArrow: {
fontSize: '1.2rem !important',
},
sidebarItemExpandArrowExpanded: {
fontSize: '1.2rem !important',
color: theme.palette.primary.main,
fontWeight: 'bold',
},
active: {
background: alpha(theme.palette.primary.light, 0.2),
},
}));
function SidebarItem({ depthStep = 10, depth = 0, expanded, item, ...rest }) {
const [collapsed, setCollapsed] = React.useState(true);
const { label, items, Icon, onClick: onClickProp } = item;
const classes = useStyles();
const history = useHistory();
const location = useLocation();
function toggleCollapse() {
setCollapsed(prevValue => !prevValue);
}
function onClick(e) {
if (Array.isArray(items)) {
toggleCollapse();
}
if (onClickProp) {
onClickProp(e, item);
history.push(item.path);
}
}
let expandIcon;
if (Array.isArray(items) && items.length) {
expandIcon = !collapsed ? (
<>
<ExpandLessIcon className={classes.sidebarItemExpandArrowExpanded} />
</>
) : (
<ExpandMoreIcon className={classes.sidebarItemExpandArrow} />
);
}
return (
<>
<ListItem
className={classes.sidebarItem}
onClick={onClick}
button
dense
className={location.pathname === item.path ? classes.active : null}
{...rest}
>
<div
style={{ paddingLeft: depth * depthStep }}
className={classes.sidebarItemContent}
>
{Icon && (
<Icon
className={classes.sidebarItemIcon}
fontSize="small"
color="primary"
/>
)}
<div className={classes.sidebarItemText}>{label}</div>
</div>
{expandIcon}
</ListItem>
<Collapse in={!collapsed} timeout="auto" unmountOnExit>
{Array.isArray(items) ? (
<List disablePadding dense>
{items.map((subItem, index) => (
<React.Fragment key={`${subItem.name}${index}`}>
{subItem === 'divider' ? (
<Divider style={{ margin: '6px 0' }} />
) : (
<SidebarItem
depth={depth + 1}
depthStep={depthStep}
item={subItem}
/>
)}
</React.Fragment>
))}
</List>
) : null}
</Collapse>
</>
);
}
function Sidebar({ items, depthStep, depth, expanded }) {
const classes = useStyles();
const { key } = useParams();
return (
<Card elevation={0} className={classes.sidebar}>
<List
disablePadding
dense
subheader={
<ListSubheader component="div" id="nested-list-subheader">
{translate('sidebarMenuSettings')}
<Typography>
<Box>{key}</Box>
</Typography>
</ListSubheader>
}
>
{items.map((sidebarItem, index) => (
<React.Fragment key={`${sidebarItem.name}${index}`}>
{sidebarItem === 'divider' ? (
<Divider style={{ margin: '6px 0' }} />
) : (
<SidebarItem
depthStep={depthStep}
depth={depth}
expanded={expanded}
item={sidebarItem}
/>
)}
</React.Fragment>
))}
</List>
</Card>
);
}
export default Sidebar;
Sidebar list items
function onClick(e, item) {}
const itemsProject = [
{
name: 'companies',
label: translate('sidebarProjectCompanies'),
Icon: CompanyIcon,
path: '/project/:id/companies',
onClick,
}
{
name: 'currencies',
label: translate('sidebarProjectCurrencies'),
Icon: CurrencyIcon,
path: '/project/:id/currencies',
onClick,
}
];
export default itemsProject;
How can I pass the ID variable on the Sidebar list items?
I thank you for your help!
You can use ES6 template literals as follows.
path: `/project/${id}/companies`
Since you already defined your path, you just need to use useHistory and navigate to the new link
import { useHistory } from 'react-router';
...
const history = useHistory();
...
// call this whenever you want to navigate
history.push(`/project/${id}/currencies`);

I cannot get the updated value from the global state (REDUX) when I use Material-UI

I cannot get the updated state of isAuthenticated when I have Material-UI code.
Is there any way that I can update the state when I have Material-UI code.
import React from "react";
import clsx from "clsx";
import { withStyles } from "#material-ui/core/styles";
import MUILink from "#material-ui/core/Link";
import AppBar from "../UI/components/AppBar";
import Toolbar, { styles as toolbarStyles } from "../UI/components/Toolbar";
import { Link } from "react-router-dom";
import { connect } from 'react-redux';
const styles = theme => ({
title: {
fontSize: 24
},
placeholder: toolbarStyles(theme).root,
toolbar: {
justifyContent: "space-between"
},
left: {
flex: 1
},
leftLinkActive: {
color: theme.palette.common.white
},
right: {
flex: 1,
display: "flex",
justifyContent: "flex-end"
},
rightLink: {
fontSize: 16,
color: theme.palette.common.white,
marginLeft: theme.spacing(3)
},
linkSecondary: {
color: theme.palette.secondary.main
}
});
const Navbar = (props,{isAuthenticated,loading}) => {
const { classes } = props;
const authLinks = (
<div className={classes.right}>
<MUILink
variant="h6"
underline="none"
component={Link} to="/log-out"
className={clsx(classes.rightLink, classes.linkSecondary)}
>
{"Log out"}
</MUILink>
</div>
);
const guestLinks = (
<div className={classes.right}>
<MUILink
color="inherit"
variant="h6"
underline="none"
component={Link} to="/sign-in"
className={classes.rightLink}
>
{"Sign In"}
</MUILink>
<MUILink
variant="h6"
underline="none"
component={Link} to="/sign-up"
className={clsx(classes.rightLink, classes.linkSecondary)}
>
{"Sign Up"}
</MUILink>
</div>
);
return (
<div>
<AppBar position="fixed">
<Toolbar className={classes.toolbar}>
<div className={classes.left} />
<MUILink
variant="h6"
underline="none"
color="inherit"
className={classes.title}
component={Link} to="/"
>
{"buzzer"}
</MUILink>
{!loading && (
<React.Fragment>{isAuthenticated ? authLinks : guestLinks}</React.Fragment>
)}
</Toolbar>
</AppBar>
<div className={classes.placeholder} />
</div>
);
};
const mapStateToProps = state =>({
isAuthenticated:state.auth.isAuthenticated,
loading:state.auth.loading
})
export default connect(mapStateToProps)((withStyles(styles)(Navbar)));
I want that the Navbar to change based on the condition of isAuthenticated. If user is authenticated I want to display only authLink, if the user is not authenticated I want to display the guestLink.
{isAuthenticated,loading} will be injected inside props, and not as a second parameter:
const Navbar = (props) => {
const { classes, isAuthenticated,loading } = props;

Resources