Problem Upgrading React application - material UI v4 to v5 - reactjs

I have this problem upgrading my react application. Basically, I followed the damn mui-v5 documentation, and I still have some erros in my app.tsx file.
import { useReactOidc, withOidcSecure } from '#axa-fr/react-oidc-context';
import { Container } from '#mui/material';
import CssBaseline from '#mui/material/CssBaseline';
import {
ThemeProvider,
StyledEngineProvider,
Theme,
} from '#mui/material/styles';
import createStyles from '#mui/styles/createStyles';
import makeStyles from '#mui/styles/makeStyles';
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { Redirect, Route, Switch } from 'react-router-dom';
import { RootState } from 'src/lib/configuration/store-configuration';
import { DarkTheme, LightTheme } from 'src/components/material-ui-theme';
import routes from 'src/components/routes/routes';
import BreadCrumbs from 'src/components/shared/breadcrumbs/breadcrumbs';
import ErrorBoundary from 'src/components/shared/error/Error';
import Footer from 'src/components/shared/footer/footer';
import Header from 'src/components/shared/header/header';
import Notifier from 'src/components/shared/notifications';
import ScrollTop from 'src/components/shared/scroll-top/scroll-top';
import Sider from 'src/components/shared/sider';
import { useTranslation } from 'react-i18next';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
display: 'flex',
},
toolbar: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: theme.spacing(0, 1),
// necessary for content to be below app bar
...theme.mixins.toolbar,
},
content: {
flexGrow: 1,
padding: theme.spacing(3),
},
container: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(1),
},
}),
);
const App = () => {
const classes = useStyles();
const { oidcUser } = useReactOidc();
const appStore = useSelector((store: RootState) => store.app);
const [drawerOpen, setDrawerOpen] = useState(false);
const handleDrawerToggle = () => {
setDrawerOpen(!drawerOpen);
};
const { i18n } = useTranslation();
useEffect(() => {
document.documentElement.lang = i18n.language;
}, [i18n.language]);
return (
<StyledEngineProvider injectFirst>
<ThemeProvider
theme={
appStore.theme === 'dark' ? DarkTheme : LightTheme
}
>
<div className={classes.root}>
<CssBaseline />
<Header handleDrawerToggle={handleDrawerToggle} />
{oidcUser ? (
<Sider
drawerOpen={drawerOpen}
handleDrawerToggle={
handleDrawerToggle
}
/>
) : null}
<main className={classes.content}>
<div id="back-to-top-anchor" />
<div className={classes.toolbar} />
<Container
maxWidth="xl"
className={classes.container}
>
<Notifier />
<BreadCrumbs />
<ErrorBoundary>
<Switch>
{routes.map(
(route, i) => (
<Route
key={
'route_' +
i
}
exact={
route.exact
}
path={
route.path
}
component={
route.secure
? withOidcSecure(
route.component,
)
: route.component
}
/>
),
)}
<Redirect to="/" />
</Switch>
</ErrorBoundary>
</Container>
<ScrollTop />
<Footer />
</main>
</div>
</ThemeProvider>
</StyledEngineProvider>
);
};
export default App;
Here is the navigator console error :
I tried to modify some imports and used:
import { createTheme } from '#material-ui/core';
const theme = createTheme();
And passing it to makestyles((theme) => ... but nothing changed.
Please guys I need your support ! :)
link for the open-source github project: https://github.com/InseeFr/sugoi-ui

Related

Logout button in custom usermenu does nothing

I have custom user menu
import React from "react";
import { UserMenu, MenuItemLink} from "react-admin";
import SettingsIcon from "#material-ui/icons/Settings";
import jwt from "jwt-decode";
const AdminUserMenu = ({ logout }) => {
var user = jwt(localStorage.getItem("token"));
return (
<UserMenu>
<MenuItemLink
to={"/Admins/" + user.id}
primaryText="Profile"
leftIcon={<SettingsIcon />}
/>
{logout}
</UserMenu>
);
};
export default AdminUserMenu;
const AdminAppBar = (props) => (
<AppBar {...props} userMenu={<AdminUserMenu />} />
);
Profile link works. But logout button does nothing. How can I make it work so that user could logout?
Try this:
const AdminUserMenu = (props) => {
var user = jwt(localStorage.getItem("token"));
return (
<UserMenu {...props} >
<MenuItemLink
to={"/Admins/" + user.id}
primaryText="Profile"
leftIcon={<SettingsIcon />}
/>
</UserMenu>
);
};
I had the same behavior that you did using the latest version. The above code from MaxAlex also didn't work for some reason.
I was able to get it work work as follows. Notice the placement of the {logout} in the ConfigurationMenu object versus in the CustomUserMenu.
import * as React from 'react';
import { forwardRef } from 'react';
import { AppBar, UserMenu, MenuItemLink, useTranslate } from 'react-admin';
import Typography from '#material-ui/core/Typography';
import SettingsIcon from '#material-ui/icons/Settings';
import { makeStyles } from '#material-ui/core/styles';
import Logo from '../Logo';
const useStyles = makeStyles({
title: {
flex: 1,
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
},
spacer: {
flex: 1,
}
});
const ConfigurationMenu = ({logout, props}) => {
const translate = useTranslate();
return (
<div>
<MenuItemLink
to="/profile"
primaryText={translate("cw.profile.title")}
leftIcon={<SettingsIcon />}
{...props}
/>
{logout}
</div>
);
};
const CustomUserMenu = (props) => (
<UserMenu {...props} >
<ConfigurationMenu />
</UserMenu>
);
const CustomAppBar = (props) => {
const classes = useStyles();
return (
<AppBar {...props} elevation={1} userMenu={<CustomUserMenu />}>
<Typography
variant="h6"
color="inherit"
className={classes.title}
id="react-admin-title"
/>
<Logo />
<span className={classes.spacer} />
</AppBar>
);
};
export default CustomAppBar;

Cant display value from array in graphql query using React

Im using React with Apollo on the frontend and i'm having trouble displaying the title and the id of the array likes. Im iterating using the method .map over the tracks array and i can access all the values in it except the values stored in the array likes. Here is the code which explains it better then words i guess :)
App.js
import React from "react";
import withStyles from "#material-ui/core/styles/withStyles";
import { Query } from 'react-apollo'
import { gql } from 'apollo-boost'
import SearchTracks from '../components/Track/SearchTracks'
import TrackList from '../components/Track/TrackList'
import CreateTrack from '../components/Track/CreateTrack'
import Loading from '../components/Shared/Loading'
import Error from '../components/Shared/Error'
const App = ({ classes }) => {
return (
<div className={classes.container}>
<SearchTracks />
<CreateTrack />
<Query query={GET_TRACKS_QUERY}>
{({ data, loading, error }) => {
if (loading) return <Loading />
if (error) return <Error error={error} />
return <TrackList tracks={data.tracks} />
}}
</Query>
</div>
);
};
const GET_TRACKS_QUERY = gql`
query getTracksQuery {
tracks {
id
title
description
url
likes {
title
id
}
postedBy {
id
username
}
}
}
`
const styles = theme => ({
container: {
margin: "0 auto",
maxWidth: 960,
padding: theme.spacing.unit * 2
}
});
export default withStyles(styles)(App);
TrackList.js
import React from "react";
import withStyles from "#material-ui/core/styles/withStyles";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemText from "#material-ui/core/ListItemText";
import Typography from "#material-ui/core/Typography";
import ExpansionPanel from "#material-ui/core/ExpansionPanel";
import ExpansionPanelDetails from "#material-ui/core/ExpansionPanelDetails";
import ExpansionPanelSummary from "#material-ui/core/ExpansionPanelSummary";
import ExpansionPanelActions from "#material-ui/core/ExpansionPanelActions";
import ExpandMoreIcon from "#material-ui/icons/ExpandMore";
import AudioPlayer from '../Shared/AudioPlayer'
import LikeTrack from './LikeTrack'
import CreateTrack from './CreateTrack'
import DeleteTrack from './DeleteTrack'
import UpdateTrack from './UpdateTrack'
import { Link } from 'react-router-dom'
const TrackList = ({ classes, tracks }) => (
<List>
{tracks.map( track => (
<ExpansionPanel key={track.id}>
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />}>
<ListItem primaryTypographyProps={{
variant: "subheading",
color: "primary"
}} className={classes.root}>
<LikeTrack />
<ListItemText primary={track.title} secondary={
<Link className={classes.link} to={`/profile/${track.postedBy.id}`}>
{track.postedBy.username}
</Link>
} />
<AudioPlayer />
</ListItem>
</ExpansionPanelSummary>
<ExpansionPanelDetails className={classes.details}>
<Typography variant="body1">
{track.description}
{track.likes.id} {/* { Value not displayed } */}
</Typography>
</ExpansionPanelDetails>
<ExpansionPanelActions>
<UpdateTrack />
<DeleteTrack />
</ExpansionPanelActions>
</ExpansionPanel>
) )}
</List>
);
const styles = {
root: {
display: "flex",
flexWrap: "wrap"
},
details: {
alignItems: "center"
},
link: {
color: "#424242",
textDecoration: "none",
"&:hover": {
color: "black"
}
}
};
export default withStyles(styles)(TrackList);
Thanks #xadm use of another map() or single track.likes[0].id works!

Dynamically update context in React Native hook

I am trying to update theme of my react native app using context API but it is throwing an error setThemeMode is not a function. (In 'setThemeMode(themeMode === 'light' ? 'dark': 'light')', 'setThemeMode' is "i")
I have taken refernce of following blog article
https://www.smashingmagazine.com/2020/01/introduction-react-context-api/
Main Error Image
ThemeContext.js
import React from 'react';
const ThemeContext = React.createContext(['light', () => {}]);
export default ThemeContext;
App.js
import React, {useState} from 'react';
import Nav from './src/navigation/Nav';
import 'react-native-gesture-handler';
import ThemeContext from './src/context/ThemeContext';
const App = () => {
const [theme] = useState("light");
return (
<>
<ThemeContext.Provider value={theme}>
<Nav />
</ThemeContext.Provider>
</>
);
};
export default App;
Settings.js
import React, {useContext} from 'react';
import {View, Text, TouchableHighlight, Alert} from 'react-native';
import Icon from 'react-native-vector-icons/dist/Ionicons';
import Switches from 'react-native-switches';
import ThemeContext from './../context/ThemeContext';
import AppTheme from './../Colors';
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
import ThemeSwitch from './ThemeSwitch';
const Settings = () => {
const [themeMode, setThemeMode] = useContext(ThemeContext);
const theme = useContext(ThemeContext);
const currentTheme = AppTheme[theme];
return (
<>
<TouchableHighlight
onPress={() => setThemeMode(themeMode === 'light' ? 'dark' : 'light')}
style={{
backgroundColor: 'black',
borderRadius: 100,
width: wp(14),
height: wp(14),
justifyContent: 'center',
alignItems: 'center',
}}>
<Icon name="md-arrow-round-back" size={wp(8)} color="white" />
</TouchableHighlight>
</>
);
};
export default Settings;
Nav.js
import React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import Welcome from './../components/Welcome';
import Settings from './../components/Settings';
import Main from './../components/Main';
const Stack = createStackNavigator();
const Nav = () => {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="Main" component={Main} />
<Stack.Screen name="Settings" component={Settings} />
<Stack.Screen name="Welcome" component={Welcome} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default Nav;
Colors.js
const AppTheme = {
light: {
name: 'light',
textColor: 'black',
backgroundColor: 'white',
},
dark: {
name: 'dark',
textColor: 'white',
backgroundColor: 'black',
},
};
export default AppTheme;
I want to dynamically update context. Pardon me for such silly bug but I am new to react and Js.
I have attached the issue image. I think I am doing something wrong with useContext because when I try to console.log(ThemeContext) it was showing undefined instead of light.
In App js ... You have to set the theme mode like
const [themeMode, setThemeMode] = useState('light');
then
<ThemeContext.Provider value={themeMode,setThemeMode}>
then wherever you want to update the value ... you can access it
const [theme,setThemeMode] = useContext(ThemeContext)
instead of create and assign state to context use the state from Context
const [themeMode, setThemeMode] = useContext(ThemeContext);
Should be
const [themeMode, setThemeMode] = useState(ThemeContext);

How to test react component with hooks using react testing library

I am trying to test a component which use useTheme hook provided by emotion.js. The theme is set during the app initialization.
Now when I write my test cases, the useTheme hook is unable to fetch the styles data as only header component is getting mounted for testing. How to mock the data provided by hooks.
app.js
import { theme } from '../src/utils/styles/themes/default';
const AppRoot = ({ path, Router }) => {
const routeRenderFunction = (props) => <RouteHandler route={props} />;
return (
<ThemeProvider theme={theme}>
<Router location={path} context={{}}>
<Switch>
{routePatterns.map((routePattern) => (
<Route key={routePattern} path={routePattern} render={routeRenderFunction} />
))}
</Switch>
</Router>
</ThemeProvider>
);
};
header.js
import React from "react";
import { css } from "emotion";
import { useTheme } from "emotion-theming";
import * as styles from "./Header.style";
const Header = ({userName = 'Becky Parsons', clinicName = 'The University of Southampton'}) => {
const theme = useTheme();
return (
<div className={css(styles.accountDetails(theme))}>
<div className={css(styles.accountContainer)}>
<div className={css(styles.accountSpecifics)}>
<h5 className={css(styles.accountDetailsH5(theme))} data-testid="user-name">{userName}</h5>
<h6 className={css(styles.accountDetailsH6(theme))} data-testid="clinic-name">
{clinicName}
</h6>
</div>
<div className={css(styles.avatar)} />
</div>
</div>
);
};
export default Header;
header.test.js
import React from 'react'
import {render} from '#testing-library/react';
import Header from './Header';
test('Check if header component loads', () => {
const { getByTestId } = render(<Header userName='Becky Parsons' clinicName='The University of Southampton'/>);
expect(getByTestId('user-name').textContent).toBe('Becky Parsons');
expect(getByTestId('clinic-name').textContent).toBe('The University of Southampton');
})
header.style.js
export const accountDetails = theme => ({
height: '70px',
backgroundColor: theme.header.backgroundColor,
textAlign: 'right',
padding: '10px 40px'
});
export const accountContainer = {
display: 'flex',
justifyContent: 'flex-end'
};
Error: Uncaught [TypeError: Cannot read property 'backgroundColor' of undefined]
You should wrap your component with ThemeProvider, try this;
test('Check if header component loads', () => {
const { getByText } = render(
<ThemeProvider theme={your theme object...}>
<Header userName='Becky Parsons' clinicName='The University of Southampton'/>
</ThemeProvider >
);
...
});
and you can look here: https://github.com/emotion-js/emotion/blob/master/packages/emotion-theming/tests/use-theme.js

Background image in react-admin Login page

I want to use a image to be put in as background image of login page in react-admin how can I do this ?
P.S: I'm using TypeScript
The Admin component have a loginPage prop. You can pass a custom component in that.
Here is an example, create your LoginPage component:
// LoginPage.js
import React from 'react';
import { Login, LoginForm } from 'react-admin';
import { withStyles } from '#material-ui/core/styles';
const styles = ({
main: { background: '#333' },
avatar: {
background: 'url(//cdn.example.com/background.jpg)',
backgroundRepeat: 'no-repeat',
backgroundSize: 'contain',
height: 80,
},
icon: { display: 'none' },
});
const CustomLoginForm = withStyles({
button: { background: '#F15922' },
})(LoginForm);
const CustomLoginPage = props => (
<Login
loginForm={<CustomLoginForm />}
{...props}
/>
);
export default withStyles(styles)(CustomLoginPage);
And use it in your Admin:
// App.js
import { Admin } from 'react-admin';
import LoginPage from './LoginPage';
export default const App = () => (
<Admin
loginPage={LoginPage}
{...props}
>
{resources}
</Admin>
);
More infos about this prop in the documentation: Admin.loginPage
For just a background image and nothing else:
https://marmelab.com/react-admin/Theming.html#using-a-custom-login-page you only need:
import { Admin, Login } from 'react-admin';
const MyLoginPage = () => <Login backgroundImage="/background.jpg" />;
const App = () => (
<Admin loginPage={MyLoginPage}>
</Admin>
);
Well, I find this solution in React Admin's issues
import React from 'react';
import { Login, LoginForm } from 'ra-ui-materialui';
import { withStyles } from '#material-ui/core/styles';
const styles = {
login: {
main: {
backgroundImage: 'url(https://source.unsplash.com/1600x900/?traffic,road)',
},
card: {
padding: '5px 0 15px 0',
},
},
form: {
button: {
height: '3em',
},
},
};
const MyLoginForm = withStyles(styles.form)(LoginForm);
const MyLogin = (props) => (
<Login loginForm={<MyLoginForm />} {...props} />
);
export default withStyles(styles.login)(MyLogin);
This is link click here

Resources