build(deps): update mui monorepo to v5.8.4 (major) (#3215)

pull/3563/head^2
James Elliott 2022-06-21 10:35:30 +10:00 committed by GitHub
parent 0a9dd4727d
commit 841e495dca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1180 additions and 533 deletions

View File

@ -17,13 +17,16 @@
} }
}, },
"dependencies": { "dependencies": {
"@emotion/cache": "11.9.3",
"@emotion/react": "11.9.3",
"@emotion/styled": "11.9.3",
"@fortawesome/fontawesome-svg-core": "6.1.1", "@fortawesome/fontawesome-svg-core": "6.1.1",
"@fortawesome/free-regular-svg-icons": "6.1.1", "@fortawesome/free-regular-svg-icons": "6.1.1",
"@fortawesome/free-solid-svg-icons": "6.1.1", "@fortawesome/free-solid-svg-icons": "6.1.1",
"@fortawesome/react-fontawesome": "0.1.18", "@fortawesome/react-fontawesome": "0.1.18",
"@material-ui/core": "4.12.4", "@mui/icons-material": "5.8.4",
"@material-ui/icons": "4.11.3", "@mui/material": "5.8.4",
"@material-ui/styles": "4.11.5", "@mui/styles": "5.8.4",
"axios": "0.27.2", "axios": "0.27.2",
"classnames": "2.3.1", "classnames": "2.3.1",
"i18next": "21.8.10", "i18next": "21.8.10",
@ -151,7 +154,7 @@
"@typescript-eslint/eslint-plugin": "5.29.0", "@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0", "@typescript-eslint/parser": "5.29.0",
"@vitejs/plugin-react": "1.3.2", "@vitejs/plugin-react": "1.3.2",
"esbuild": "0.14.46", "esbuild": "0.14.17",
"esbuild-jest": "0.5.0", "esbuild-jest": "0.5.0",
"eslint": "8.18.0", "eslint": "8.18.0",
"eslint-config-prettier": "8.5.0", "eslint-config-prettier": "8.5.0",

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,9 @@
import React, { useState, useEffect, Suspense } from "react"; import React, { useState, useEffect, Suspense } from "react";
import createCache from "@emotion/cache";
import { CacheProvider } from "@emotion/react";
import { config as faConfig } from "@fortawesome/fontawesome-svg-core"; import { config as faConfig } from "@fortawesome/fontawesome-svg-core";
import { CssBaseline, ThemeProvider } from "@material-ui/core"; import { CssBaseline, ThemeProvider } from "@mui/material";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import NotificationBar from "@components/NotificationBar"; import NotificationBar from "@components/NotificationBar";
@ -51,9 +53,20 @@ function Theme() {
} }
} }
const App: React.FC = () => { export interface Props {
nonce?: string;
}
const App: React.FC<Props> = (props: Props) => {
const [notification, setNotification] = useState(null as Notification | null); const [notification, setNotification] = useState(null as Notification | null);
const [theme, setTheme] = useState(Theme()); const [theme, setTheme] = useState(Theme());
const cache = createCache({
key: "authelia",
nonce: props.nonce,
prepend: true,
});
useEffect(() => { useEffect(() => {
if (getTheme() === "auto") { if (getTheme() === "auto") {
const query = window.matchMedia("(prefers-color-scheme: dark)"); const query = window.matchMedia("(prefers-color-scheme: dark)");
@ -66,6 +79,7 @@ const App: React.FC = () => {
} }
}, []); }, []);
return ( return (
<CacheProvider value={cache}>
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<Suspense fallback={<BaseLoadingPage message={"Loading"} />}> <Suspense fallback={<BaseLoadingPage message={"Loading"} />}>
<CssBaseline /> <CssBaseline />
@ -95,6 +109,7 @@ const App: React.FC = () => {
</NotificationsContext.Provider> </NotificationsContext.Provider>
</Suspense> </Suspense>
</ThemeProvider> </ThemeProvider>
</CacheProvider>
); );
}; };

View File

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import { Link } from "@material-ui/core"; import { Box, Link, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import AppleStore from "@assets/images/applestore-badge.svg"; import AppleStore from "@assets/images/applestore-badge.svg";
import GooglePlay from "@assets/images/googleplay-badge.svg"; import GooglePlay from "@assets/images/googleplay-badge.svg";
@ -17,17 +18,21 @@ export interface Props {
const AppStoreBadges = function (props: Props) { const AppStoreBadges = function (props: Props) {
const target = props.targetBlank ? "_blank" : undefined; const target = props.targetBlank ? "_blank" : undefined;
const width = props.iconSize; const styles = makeStyles((theme: Theme) => ({
badge: {
width: props.iconSize,
},
}))();
return ( return (
<div className={props.className}> <Box className={props.className}>
<Link href={props.googlePlayLink} target={target}> <Link href={props.googlePlayLink} target={target} underline="hover">
<img src={GooglePlay} alt="google play" style={{ width }} /> <img src={GooglePlay} alt="google play" className={styles.badge} />
</Link> </Link>
<Link href={props.appleStoreLink} target={target}> <Link href={props.appleStoreLink} target={target} underline="hover">
<img src={AppleStore} alt="apple store" style={{ width }} /> <img src={AppleStore} alt="apple store" className={styles.badge} />
</Link> </Link>
</div> </Box>
); );
}; };

View File

@ -1,15 +0,0 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import ColoredSnackbarContent from "@components/ColoredSnackbarContent";
it("renders without crashing", () => {
render(<ColoredSnackbarContent level="success" message="" />);
expect(screen.getByRole("alert")).toHaveTextContent("");
});
it("should contain the message", () => {
render(<ColoredSnackbarContent level="success" message="this is a success" />);
expect(screen.getByRole("alert")).toHaveTextContent("this is a success");
});

View File

@ -1,73 +0,0 @@
import React from "react";
import { makeStyles, SnackbarContent } from "@material-ui/core";
import { amber, green } from "@material-ui/core/colors";
import { SnackbarContentProps } from "@material-ui/core/SnackbarContent";
import CheckCircleIcon from "@material-ui/icons/CheckCircle";
import ErrorIcon from "@material-ui/icons/Error";
import InfoIcon from "@material-ui/icons/Info";
import WarningIcon from "@material-ui/icons/Warning";
import classnames from "classnames";
const variantIcon = {
success: CheckCircleIcon,
warning: WarningIcon,
error: ErrorIcon,
info: InfoIcon,
};
export type Level = keyof typeof variantIcon;
export interface Props extends SnackbarContentProps {
className?: string;
level: Level;
message: string;
}
const ColoredSnackbarContent = function (props: Props) {
const classes = useStyles();
const Icon = variantIcon[props.level];
const { className, variant, message, ...others } = props;
return (
<SnackbarContent
className={classnames(classes[props.level], className)}
message={
<span className={classes.message}>
<Icon className={classnames(classes.icon, classes.iconVariant)} />
{message}
</span>
}
{...others}
/>
);
};
export default ColoredSnackbarContent;
const useStyles = makeStyles((theme) => ({
success: {
backgroundColor: green[600],
},
error: {
backgroundColor: theme.palette.error.dark,
},
info: {
backgroundColor: theme.palette.primary.main,
},
warning: {
backgroundColor: amber[700],
},
icon: {
fontSize: 20,
},
iconVariant: {
opacity: 0.9,
marginRight: theme.spacing(1),
},
message: {
display: "flex",
alignItems: "center",
},
}));

View File

@ -1,9 +1,15 @@
import React from "react"; import React from "react";
import { createTheme } from "@mui/material/styles";
import { ThemeProvider } from "@mui/styles";
import { render } from "@testing-library/react"; import { render } from "@testing-library/react";
import FixedTextField from "@components/FixedTextField"; import FixedTextField from "@components/FixedTextField";
it("renders without crashing", () => { it("renders without crashing", () => {
render(<FixedTextField />); render(
<ThemeProvider theme={createTheme()}>
<FixedTextField />
</ThemeProvider>,
);
}); });

View File

@ -1,7 +1,8 @@
import React from "react"; import React from "react";
import { makeStyles } from "@material-ui/core"; import { Theme } from "@mui/material/styles";
import TextField, { TextFieldProps } from "@material-ui/core/TextField"; import TextField, { TextFieldProps } from "@mui/material/TextField";
import makeStyles from "@mui/styles/makeStyles";
/** /**
* This component fixes outlined TextField * This component fixes outlined TextField
@ -10,16 +11,16 @@ import TextField, { TextFieldProps } from "@material-ui/core/TextField";
* @param props the TextField props * @param props the TextField props
*/ */
const FixedTextField = function (props: TextFieldProps) { const FixedTextField = function (props: TextFieldProps) {
const style = useStyles(); const styles = useStyles();
return ( return (
<TextField <TextField
{...props} {...props}
InputLabelProps={{ InputLabelProps={{
classes: { classes: {
root: style.label, root: styles.label,
}, },
}} }}
inputProps={{ autoCapitalize: props.autoCapitalize }}
> >
{props.children} {props.children}
</TextField> </TextField>
@ -28,7 +29,7 @@ const FixedTextField = function (props: TextFieldProps) {
export default FixedTextField; export default FixedTextField;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
label: { label: {
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.default,
paddingLeft: theme.spacing(0.1), paddingLeft: theme.spacing(0.1),

View File

@ -1,13 +1,23 @@
import React from "react"; import React from "react";
import { createTheme } from "@mui/material/styles";
import { ThemeProvider } from "@mui/styles";
import { render } from "@testing-library/react"; import { render } from "@testing-library/react";
import LinearProgressBar from "@components/LinearProgressBar"; import LinearProgressBar from "@components/LinearProgressBar";
it("renders without crashing", () => { it("renders without crashing", () => {
render(<LinearProgressBar value={40} />); render(
<ThemeProvider theme={createTheme()}>
<LinearProgressBar value={40} />)
</ThemeProvider>,
);
}); });
it("renders adjusted height without crashing", () => { it("renders adjusted height without crashing", () => {
render(<LinearProgressBar value={40} height={2} />); render(
<ThemeProvider theme={createTheme()}>
<LinearProgressBar value={40} height={2} />
</ThemeProvider>,
);
}); });

View File

@ -1,17 +1,16 @@
import React from "react"; import React from "react";
import { makeStyles, LinearProgress } from "@material-ui/core"; import { LinearProgress, Theme } from "@mui/material";
import { CSSProperties } from "@material-ui/styles"; import makeStyles from "@mui/styles/makeStyles";
export interface Props { export interface Props {
value: number; value: number;
height?: number; height?: string | number;
className?: string; className?: string;
style?: CSSProperties;
} }
const LinearProgressBar = function (props: Props) { const LinearProgressBar = function (props: Props) {
const style = makeStyles((theme) => ({ const styles = makeStyles((theme: Theme) => ({
progressRoot: { progressRoot: {
height: props.height ? props.height : theme.spacing(), height: props.height ? props.height : theme.spacing(),
}, },
@ -19,13 +18,13 @@ const LinearProgressBar = function (props: Props) {
transition: "transform .2s linear", transition: "transform .2s linear",
}, },
}))(); }))();
return ( return (
<LinearProgress <LinearProgress
style={props.style as React.CSSProperties}
variant="determinate" variant="determinate"
classes={{ classes={{
root: style.progressRoot, root: styles.progressRoot,
bar1Determinate: style.transition, bar1Determinate: styles.transition,
}} }}
value={props.value} value={props.value}
className={props.className} className={props.className}

View File

@ -1,8 +1,7 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Snackbar } from "@material-ui/core"; import { Alert, Slide, SlideProps, Snackbar } from "@mui/material";
import ColoredSnackbarContent from "@components/ColoredSnackbarContent";
import { useNotifications } from "@hooks/NotificationsContext"; import { useNotifications } from "@hooks/NotificationsContext";
import { Notification } from "@models/Notifications"; import { Notification } from "@models/Notifications";
@ -10,12 +9,18 @@ export interface Props {
onClose: () => void; onClose: () => void;
} }
type NotificationBarTransitionProps = Omit<SlideProps, "direction">;
function NotificationBarTransition(props: NotificationBarTransitionProps) {
return <Slide {...props} direction={"left"} />;
}
const NotificationBar = function (props: Props) { const NotificationBar = function (props: Props) {
const [tmpNotification, setTmpNotification] = useState(null as Notification | null); const [tmpNotification, setTmpNotification] = useState(null as Notification | null);
const { notification } = useNotifications(); const { notification } = useNotifications();
useEffect(() => { useEffect(() => {
if (notification && notification !== null) { if (notification) {
setTmpNotification(notification); setTmpNotification(notification);
} }
}, [notification, setTmpNotification]); }, [notification, setTmpNotification]);
@ -28,15 +33,18 @@ const NotificationBar = function (props: Props) {
anchorOrigin={{ vertical: "top", horizontal: "right" }} anchorOrigin={{ vertical: "top", horizontal: "right" }}
autoHideDuration={tmpNotification ? tmpNotification.timeout * 1000 : 10000} autoHideDuration={tmpNotification ? tmpNotification.timeout * 1000 : 10000}
onClose={props.onClose} onClose={props.onClose}
TransitionComponent={NotificationBarTransition}
TransitionProps={{ TransitionProps={{
onExited: () => setTmpNotification(null), onExited: () => setTmpNotification(null),
}} }}
> >
<ColoredSnackbarContent {tmpNotification ? (
className="notification" <Alert severity={tmpNotification.level} variant={"filled"} elevation={6} className={"notification"}>
level={tmpNotification ? tmpNotification.level : "info"} {tmpNotification.message}
message={tmpNotification ? tmpNotification.message : ""} </Alert>
/> ) : (
<Alert severity={"success"} elevation={6} variant={"filled"} className={"notification"} />
)}
</Snackbar> </Snackbar>
); );
}; };

View File

@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { makeStyles } from "@material-ui/core"; import { Box, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames"; import classnames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import zxcvbn from "zxcvbn"; import zxcvbn from "zxcvbn";
@ -13,20 +14,12 @@ export interface Props {
} }
const PasswordMeter = function (props: Props) { const PasswordMeter = function (props: Props) {
const { t: translate } = useTranslation();
const [progressColor] = useState(["#D32F2F", "#FF5722", "#FFEB3B", "#AFB42B", "#62D32F"]); const [progressColor] = useState(["#D32F2F", "#FF5722", "#FFEB3B", "#AFB42B", "#62D32F"]);
const [passwordScore, setPasswordScore] = useState(0); const [passwordScore, setPasswordScore] = useState(0);
const [maxScores, setMaxScores] = useState(0); const [maxScores, setMaxScores] = useState(0);
const [feedback, setFeedback] = useState(""); const [feedback, setFeedback] = useState("");
const { t: translate } = useTranslation();
const style = makeStyles((theme) => ({
progressBar: {
height: "5px",
marginTop: "2px",
backgroundColor: "red",
width: "50%",
transition: "width .5s linear",
},
}))();
useEffect(() => { useEffect(() => {
const password = props.value; const password = props.value;
@ -106,17 +99,23 @@ const PasswordMeter = function (props: Props) {
} }
}, [props, translate]); }, [props, translate]);
return ( const styles = makeStyles((theme: Theme) => ({
<div style={{ width: "100%" }}> progressBar: {
<div height: "5px",
title={feedback} marginTop: "2px",
className={classnames(style.progressBar)}
style={{
width: `${(passwordScore + 1) * (100 / maxScores)}%`,
backgroundColor: progressColor[passwordScore], backgroundColor: progressColor[passwordScore],
}} width: `${(passwordScore + 1) * (100 / maxScores)}%`,
/> transition: "width .5s linear",
</div> },
progressContainer: {
width: "100%",
},
}))();
return (
<Box className={styles.progressContainer}>
<Box title={feedback} className={classnames(styles.progressBar)} />
</Box>
); );
}; };

View File

@ -1,32 +1,25 @@
import React, { Fragment } from "react"; import React, { Fragment } from "react";
import { Tooltip, Typography } from "@material-ui/core"; import { Tooltip, Typography } from "@mui/material";
import { Variant } from "@material-ui/core/styles/createTypography"; import { Variant } from "@mui/material/styles/createTypography";
import { CSSProperties } from "@material-ui/styles";
export interface Props { export interface Props {
variant: Variant; variant: Variant;
value?: string; value?: string;
style?: CSSProperties;
tooltip?: string; tooltip?: string;
tooltipStyle?: CSSProperties;
} }
export default function TypographyWithTooltip(props: Props): JSX.Element { export default function TypographyWithTooltip(props: Props): JSX.Element {
return ( return (
<Fragment> <Fragment>
{props.tooltip ? ( {props.tooltip ? (
<Tooltip title={props.tooltip} style={props.tooltipStyle}> <Tooltip title={props.tooltip}>
<Typography variant={props.variant} style={props.style}> <Typography variant={props.variant}>{props.value}</Typography>
{props.value}
</Typography>
</Tooltip> </Tooltip>
) : ( ) : (
<Typography variant={props.variant} style={props.style}> <Typography variant={props.variant}>{props.value}</Typography>
{props.value}
</Typography>
)} )}
</Fragment> </Fragment>
); );

View File

@ -1,6 +1,7 @@
import { createContext, useContext, useRef } from "react"; import { createContext, useContext, useRef } from "react";
import { Level } from "@components/ColoredSnackbarContent"; import { AlertColor } from "@mui/material";
import { Notification } from "@models/Notifications"; import { Notification } from "@models/Notifications";
const defaultOptions = { const defaultOptions = {
@ -19,7 +20,7 @@ export default NotificationsContext;
export function useNotifications() { export function useNotifications() {
let useNotificationsProps = useContext(NotificationsContext); let useNotificationsProps = useContext(NotificationsContext);
const notificationBuilder = (level: Level) => { const notificationBuilder = (level: AlertColor) => {
return (message: string, timeout?: number) => { return (message: string, timeout?: number) => {
useNotificationsProps.setNotification({ useNotificationsProps.setNotification({
level, level,

View File

@ -7,8 +7,9 @@ import App from "@root/App";
import * as serviceWorker from "@root/serviceWorker"; import * as serviceWorker from "@root/serviceWorker";
import "@i18n/index.ts"; import "@i18n/index.ts";
const nonce = document.head.querySelector("[property=csp-nonce][content]")?.getAttribute("content") || undefined;
const root = createRoot(document.getElementById("root")!); const root = createRoot(document.getElementById("root")!);
root.render(<App />); root.render(<App nonce={nonce} />);
// If you want your app to work offline and load faster, you can change // If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls. // unregister() to register() below. Note this comes with some pitfalls.

View File

@ -1,7 +1,8 @@
import React, { ReactNode, useEffect } from "react"; import React, { ReactNode, useEffect } from "react";
import { Grid, makeStyles, Container, Link } from "@material-ui/core"; import { Grid, Container, Link, Theme } from "@mui/material";
import { grey } from "@material-ui/core/colors"; import { grey } from "@mui/material/colors";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ReactComponent as UserSvg } from "@assets/images/user.svg"; import { ReactComponent as UserSvg } from "@assets/images/user.svg";
@ -18,20 +19,22 @@ export interface Props {
showBrand?: boolean; showBrand?: boolean;
} }
const url = "https://www.authelia.com";
const LoginLayout = function (props: Props) { const LoginLayout = function (props: Props) {
const style = useStyles(); const styles = useStyles();
const logo = getLogoOverride() ? ( const logo = getLogoOverride() ? (
<img src="./static/media/logo.png" alt="Logo" className={style.icon} /> <img src="./static/media/logo.png" alt="Logo" className={styles.icon} />
) : ( ) : (
<UserSvg className={style.icon} /> <UserSvg className={styles.icon} />
); );
const { t: translate } = useTranslation(); const { t: translate } = useTranslation();
useEffect(() => { useEffect(() => {
document.title = `${translate("Login")} - Authelia`; document.title = `${translate("Login")} - Authelia`;
}, [translate]); }, [translate]);
return ( return (
<Grid id={props.id} className={style.root} container spacing={0} alignItems="center" justifyContent="center"> <Grid id={props.id} className={styles.root} container spacing={0} alignItems="center" justifyContent="center">
<Container maxWidth="xs" className={style.rootContainer}> <Container maxWidth="xs" className={styles.rootContainer}>
<Grid container> <Grid container>
<Grid item xs={12}> <Grid item xs={12}>
{logo} {logo}
@ -50,16 +53,12 @@ const LoginLayout = function (props: Props) {
/> />
</Grid> </Grid>
) : null} ) : null}
<Grid item xs={12} className={style.body}> <Grid item xs={12} className={styles.body}>
{props.children} {props.children}
</Grid> </Grid>
{props.showBrand ? ( {props.showBrand ? (
<Grid item xs={12}> <Grid item xs={12}>
<Link <Link href={url} target="_blank" underline="hover" className={styles.poweredBy}>
href="https://github.com/authelia/authelia"
target="_blank"
className={style.poweredBy}
>
{translate("Powered by")} Authelia {translate("Powered by")} Authelia
</Link> </Link>
</Grid> </Grid>
@ -72,7 +71,7 @@ const LoginLayout = function (props: Props) {
export default LoginLayout; export default LoginLayout;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
root: { root: {
minHeight: "90vh", minHeight: "90vh",
textAlign: "center", textAlign: "center",

View File

@ -1,7 +1,7 @@
import { Level } from "@components/ColoredSnackbarContent"; import { AlertColor } from "@mui/material";
export interface Notification { export interface Notification {
message: string; message: string;
level: Level; level: AlertColor;
timeout: number; timeout: number;
} }

View File

@ -1,4 +1,4 @@
import { createTheme } from "@material-ui/core/styles"; import { createTheme } from "@mui/material/styles";
const Dark = createTheme({ const Dark = createTheme({
custom: { custom: {
@ -6,10 +6,81 @@ const Dark = createTheme({
loadingBar: "#fff", loadingBar: "#fff",
}, },
palette: { palette: {
type: "dark", mode: "dark",
primary: { primary: {
main: "#1976d2", main: "#1976d2",
}, },
secondary: {
light: "#ff4081",
main: "#f50057",
dark: "#c51162",
contrastText: "#ffffff",
},
error: {
light: "#e57373",
main: "#f44336",
dark: "#d32f2f",
contrastText: "#ffffff",
},
warning: {
light: "#ffb74d",
main: "#ff9800",
dark: "#f57c00",
contrastText: "rgba(0, 0, 0, 0.87)",
},
info: {
light: "#64b5f6",
main: "#2196f3",
dark: "#1976d2",
contrastText: "#ffffff",
},
success: {
light: "#81c784",
main: "#4caf50",
dark: "#388e3c",
contrastText: "rgba(0, 0, 0, 0.87)",
},
grey: {
"50": "#fafafa",
"100": "#f5f5f5",
"200": "#eeeeee",
"300": "#e0e0e0",
"400": "#bdbdbd",
"500": "#9e9e9e",
"600": "#757575",
"700": "#616161",
"800": "#424242",
"900": "#212121",
A100: "#d5d5d5",
A200: "#aaaaaa",
A400: "#303030",
A700: "#616161",
},
contrastThreshold: 3,
tonalOffset: 0.2,
text: {
primary: "#fff",
secondary: "rgba(255, 255, 255, 0.7)",
disabled: "rgba(255, 255, 255, 0.5)",
},
divider: "rgba(255, 255, 255, 0.12)",
background: {
paper: "#424242",
default: "#303030",
},
action: {
active: "#fff",
hover: "rgba(255, 255, 255, 0.08)",
hoverOpacity: 0.08,
selected: "rgba(255, 255, 255, 0.16)",
selectedOpacity: 0.16,
disabled: "rgba(255, 255, 255, 0.3)",
disabledBackground: "rgba(255, 255, 255, 0.12)",
disabledOpacity: 0.38,
focus: "rgba(255, 255, 255, 0.12)",
focusOpacity: 0.12,
activatedOpacity: 0.24,
},
}, },
}); });

View File

@ -1,4 +1,4 @@
import { createTheme } from "@material-ui/core/styles"; import { createTheme } from "@mui/material/styles";
const Grey = createTheme({ const Grey = createTheme({
custom: { custom: {
@ -6,16 +6,85 @@ const Grey = createTheme({
loadingBar: "#929aa5", loadingBar: "#929aa5",
}, },
palette: { palette: {
mode: "dark",
primary: { primary: {
main: "#929aa5", main: "#929aa5",
}, },
secondary: {
light: "#ff4081",
main: "#f50057",
dark: "#c51162",
contrastText: "#ffffff",
},
error: {
light: "#e57373",
main: "#f44336",
dark: "#d32f2f",
contrastText: "#ffffff",
},
warning: {
light: "#ffb74d",
main: "#ff9800",
dark: "#f57c00",
contrastText: "rgba(0, 0, 0, 0.87)",
},
info: {
light: "#64b5f6",
main: "#2196f3",
dark: "#1976d2",
contrastText: "#ffffff",
},
success: {
light: "#81c784",
main: "#4caf50",
dark: "#388e3c",
contrastText: "rgba(0, 0, 0, 0.87)",
},
grey: {
"50": "#fafafa",
"100": "#f5f5f5",
"200": "#eeeeee",
"300": "#e0e0e0",
"400": "#bdbdbd",
"500": "#9e9e9e",
"600": "#757575",
"700": "#616161",
"800": "#424242",
"900": "#212121",
A100: "#d5d5d5",
A200: "#aaaaaa",
A400: "#303030",
A700: "#616161",
},
contrastThreshold: 3,
tonalOffset: 0.2,
text: {
primary: "#929aa5",
secondary: "rgba(0, 0, 0, 0.54)",
disabled: "rgba(0, 0, 0, 0.38)",
},
divider: "rgba(0, 0, 0, 0.12)",
background: { background: {
default: "#2f343e",
paper: "#2f343e", paper: "#2f343e",
default: "#2f343e",
},
action: {
active: "#929aa5",
hover: "#929aa5",
hoverOpacity: 0.04,
selected: "#929aa5",
selectedOpacity: 0.08,
disabled: "rgba(0, 0, 0, 0.26)",
disabledBackground: "rgba(0, 0, 0, 0.12)",
disabledOpacity: 0.38,
focus: "rgba(0, 0, 0, 0.12)",
focusOpacity: 0.12,
activatedOpacity: 0.12,
}, },
}, },
overrides: { components: {
MuiCssBaseline: { MuiCssBaseline: {
styleOverrides: {
"@global": { "@global": {
body: { body: {
backgroundColor: "#2f343e", backgroundColor: "#2f343e",
@ -23,7 +92,9 @@ const Grey = createTheme({
}, },
}, },
}, },
},
MuiOutlinedInput: { MuiOutlinedInput: {
styleOverrides: {
root: { root: {
"& $notchedOutline": { "& $notchedOutline": {
borderColor: "#929aa5", borderColor: "#929aa5",
@ -38,22 +109,29 @@ const Grey = createTheme({
}, },
notchedOutline: {}, notchedOutline: {},
}, },
},
MuiCheckbox: { MuiCheckbox: {
styleOverrides: {
root: { root: {
color: "#929aa5", color: "#929aa5",
}, },
}, },
},
MuiInputBase: { MuiInputBase: {
styleOverrides: {
input: { input: {
color: "#929aa5", color: "#929aa5",
}, },
}, },
},
MuiInputLabel: { MuiInputLabel: {
styleOverrides: {
root: { root: {
color: "#929aa5", color: "#929aa5",
}, },
}, },
}, },
},
}); });
export default Grey; export default Grey;

View File

@ -1,4 +1,4 @@
import { createTheme } from "@material-ui/core/styles"; import { createTheme } from "@mui/material/styles";
const Light = createTheme({ const Light = createTheme({
custom: { custom: {
@ -6,12 +6,80 @@ const Light = createTheme({
loadingBar: "#000", loadingBar: "#000",
}, },
palette: { palette: {
mode: "light",
primary: { primary: {
main: "#1976d2", main: "#1976d2",
}, },
secondary: {
light: "#ff4081",
main: "#f50057",
dark: "#c51162",
contrastText: "#ffffff",
},
error: {
light: "#e57373",
main: "#f44336",
dark: "#d32f2f",
contrastText: "#ffffff",
},
warning: {
light: "#ffb74d",
main: "#ff9800",
dark: "#f57c00",
contrastText: "rgba(0, 0, 0, 0.87)",
},
info: {
light: "#64b5f6",
main: "#2196f3",
dark: "#1976d2",
contrastText: "#ffffff",
},
success: {
light: "#81c784",
main: "#4caf50",
dark: "#388e3c",
contrastText: "rgba(0, 0, 0, 0.87)",
},
grey: {
"50": "#fafafa",
"100": "#f5f5f5",
"200": "#eeeeee",
"300": "#e0e0e0",
"400": "#bdbdbd",
"500": "#9e9e9e",
"600": "#757575",
"700": "#616161",
"800": "#424242",
"900": "#212121",
A100: "#d5d5d5",
A200: "#aaaaaa",
A400: "#303030",
A700: "#616161",
},
contrastThreshold: 3,
tonalOffset: 0.2,
text: {
primary: "rgba(0, 0, 0, 0.87)",
secondary: "rgba(0, 0, 0, 0.54)",
disabled: "rgba(0, 0, 0, 0.38)",
},
divider: "rgba(0, 0, 0, 0.12)",
background: { background: {
default: "#fff",
paper: "#fff", paper: "#fff",
default: "#fff",
},
action: {
active: "rgba(0, 0, 0, 0.54)",
hover: "rgba(0, 0, 0, 0.04)",
hoverOpacity: 0.04,
selected: "rgba(0, 0, 0, 0.08)",
selectedOpacity: 0.08,
disabled: "rgba(0, 0, 0, 0.26)",
disabledBackground: "rgba(0, 0, 0, 0.12)",
disabledOpacity: 0.38,
focus: "rgba(0, 0, 0, 0.12)",
focusOpacity: 0.12,
activatedOpacity: 0.12,
}, },
}, },
}); });

View File

@ -1,18 +1,28 @@
declare module "@material-ui/core/styles/createTheme" { import React from "react";
import { Theme } from "@mui/material";
declare module "@mui/material/styles" {
interface Theme { interface Theme {
custom: { custom: {
icon: React.CSSProperties["color"]; icon: React.CSSProperties["color"];
loadingBar: React.CSSProperties["color"]; loadingBar: React.CSSProperties["color"];
}; };
} }
interface ThemeOptions { interface ThemeOptions {
custom: { custom?: {
icon: React.CSSProperties["color"]; icon?: React.CSSProperties["color"];
loadingBar: React.CSSProperties["color"]; loadingBar?: React.CSSProperties["color"];
}; };
} }
} }
declare module "@mui/styles/defaultTheme" {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface DefaultTheme extends Theme {}
}
export { default as Light } from "@themes/Light"; export { default as Light } from "@themes/Light";
export { default as Dark } from "@themes/Dark"; export { default as Dark } from "@themes/Dark";
export { default as Grey } from "@themes/Grey"; export { default as Grey } from "@themes/Grey";

View File

@ -2,10 +2,11 @@ import React, { useEffect, useCallback, useState } from "react";
import { IconDefinition, faCopy, faKey, faTimesCircle } from "@fortawesome/free-solid-svg-icons"; import { IconDefinition, faCopy, faKey, faTimesCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { makeStyles, Typography, Button, IconButton, Link, CircularProgress, TextField } from "@material-ui/core"; import { Typography, Button, IconButton, Link, CircularProgress, TextField, Theme } from "@mui/material";
import { red } from "@material-ui/core/colors"; import { red } from "@mui/material/colors";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames"; import classnames from "classnames";
import QRCode from "qrcode.react"; import { QRCodeSVG } from "qrcode.react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
@ -18,7 +19,7 @@ import { completeTOTPRegistrationProcess } from "@services/RegisterDevice";
import { extractIdentityToken } from "@utils/IdentityToken"; import { extractIdentityToken } from "@utils/IdentityToken";
const RegisterOneTimePassword = function () { const RegisterOneTimePassword = function () {
const style = useStyles(); const styles = useStyles();
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
// The secret retrieved from the API is all is ok. // The secret retrieved from the API is all is ok.
@ -72,39 +73,40 @@ const RegisterOneTimePassword = function () {
function SecretButton(text: string | undefined, action: string, icon: IconDefinition) { function SecretButton(text: string | undefined, action: string, icon: IconDefinition) {
return ( return (
<IconButton <IconButton
className={style.secretButtons} className={styles.secretButtons}
color="primary" color="primary"
onClick={() => { onClick={() => {
navigator.clipboard.writeText(`${text}`); navigator.clipboard.writeText(`${text}`);
createSuccessNotification(`${action}`); createSuccessNotification(`${action}`);
}} }}
size="large"
> >
<FontAwesomeIcon icon={icon} /> <FontAwesomeIcon icon={icon} />
</IconButton> </IconButton>
); );
} }
const qrcodeFuzzyStyle = isLoading || hasErrored ? style.fuzzy : undefined; const qrcodeFuzzyStyle = isLoading || hasErrored ? styles.fuzzy : undefined;
return ( return (
<LoginLayout title={translate("Scan QR Code")}> <LoginLayout title={translate("Scan QR Code")}>
<div className={style.root}> <div className={styles.root}>
<div className={style.googleAuthenticator}> <div className={styles.googleAuthenticator}>
<Typography className={style.googleAuthenticatorText}> <Typography className={styles.googleAuthenticatorText}>
{translate("Need Google Authenticator?")} {translate("Need Google Authenticator?")}
</Typography> </Typography>
<AppStoreBadges <AppStoreBadges
iconSize={128} iconSize={128}
targetBlank targetBlank
className={style.googleAuthenticatorBadges} className={styles.googleAuthenticatorBadges}
googlePlayLink={GoogleAuthenticator.googlePlay} googlePlayLink={GoogleAuthenticator.googlePlay}
appleStoreLink={GoogleAuthenticator.appleStore} appleStoreLink={GoogleAuthenticator.appleStore}
/> />
</div> </div>
<div className={classnames(qrcodeFuzzyStyle, style.qrcodeContainer)}> <div className={classnames(qrcodeFuzzyStyle, styles.qrcodeContainer)}>
<Link href={secretURL}> <Link href={secretURL} underline="hover">
<QRCode value={secretURL} className={style.qrcode} size={256} /> <QRCodeSVG value={secretURL} className={styles.qrcode} size={256} />
{!hasErrored && isLoading ? <CircularProgress className={style.loader} size={128} /> : null} {!hasErrored && isLoading ? <CircularProgress className={styles.loader} size={128} /> : null}
{hasErrored ? <FontAwesomeIcon className={style.failureIcon} icon={faTimesCircle} /> : null} {hasErrored ? <FontAwesomeIcon className={styles.failureIcon} icon={faTimesCircle} /> : null}
</Link> </Link>
</div> </div>
<div> <div>
@ -112,7 +114,7 @@ const RegisterOneTimePassword = function () {
<TextField <TextField
id="secret-url" id="secret-url"
label={translate("Secret")} label={translate("Secret")}
className={style.secret} className={styles.secret}
value={secretURL} value={secretURL}
InputProps={{ InputProps={{
readOnly: true, readOnly: true,
@ -129,7 +131,7 @@ const RegisterOneTimePassword = function () {
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
className={style.doneButton} className={styles.doneButton}
onClick={handleDoneClick} onClick={handleDoneClick}
disabled={isLoading} disabled={isLoading}
> >
@ -142,7 +144,7 @@ const RegisterOneTimePassword = function () {
export default RegisterOneTimePassword; export default RegisterOneTimePassword;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
root: { root: {
paddingTop: theme.spacing(4), paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4), paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { Button, makeStyles, Typography } from "@material-ui/core"; import { Button, Theme, Typography } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import FingerTouchIcon from "@components/FingerTouchIcon"; import FingerTouchIcon from "@components/FingerTouchIcon";
@ -12,7 +13,7 @@ import { performAttestationCeremony } from "@services/Webauthn";
import { extractIdentityToken } from "@utils/IdentityToken"; import { extractIdentityToken } from "@utils/IdentityToken";
const RegisterWebauthn = function () { const RegisterWebauthn = function () {
const style = useStyles(); const styles = useStyles();
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
const { createErrorNotification } = useNotifications(); const { createErrorNotification } = useNotifications();
@ -84,10 +85,10 @@ const RegisterWebauthn = function () {
return ( return (
<LoginLayout title="Touch Security Key"> <LoginLayout title="Touch Security Key">
<div className={style.icon}> <div className={styles.icon}>
<FingerTouchIcon size={64} animated /> <FingerTouchIcon size={64} animated />
</div> </div>
<Typography className={style.instruction}>Touch the token on your security key</Typography> <Typography className={styles.instruction}>Touch the token on your security key</Typography>
<Button color="primary" onClick={handleBackClick}> <Button color="primary" onClick={handleBackClick}>
Retry Retry
</Button> </Button>
@ -100,7 +101,7 @@ const RegisterWebauthn = function () {
export default RegisterWebauthn; export default RegisterWebauthn;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
icon: { icon: {
paddingTop: theme.spacing(4), paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4), paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import { Grid, Typography, useTheme } from "@material-ui/core"; import { Grid, Theme, Typography, useTheme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import ReactLoading from "react-loading"; import ReactLoading from "react-loading";
export interface Props { export interface Props {
@ -9,9 +10,11 @@ export interface Props {
const BaseLoadingPage = function (props: Props) { const BaseLoadingPage = function (props: Props) {
const theme = useTheme(); const theme = useTheme();
const styles = useStyles();
return ( return (
<Grid container alignItems="center" justifyContent="center" style={{ minHeight: "100vh" }}> <Grid container className={styles.gridOuter}>
<Grid item style={{ textAlign: "center", display: "inline-block" }}> <Grid item className={styles.gridInner}>
<ReactLoading width={64} height={64} color={theme.custom.loadingBar} type="bars" /> <ReactLoading width={64} height={64} color={theme.custom.loadingBar} type="bars" />
<Typography>{props.message}...</Typography> <Typography>{props.message}...</Typography>
</Grid> </Grid>
@ -20,3 +23,15 @@ const BaseLoadingPage = function (props: Props) {
}; };
export default BaseLoadingPage; export default BaseLoadingPage;
const useStyles = makeStyles((theme: Theme) => ({
gridOuter: {
alignItems: "center",
justifyContent: "center",
minHeight: "100vh",
},
gridInner: {
textAlign: "center",
display: "inline-block",
},
}));

View File

@ -1,16 +1,17 @@
import React from "react"; import React from "react";
import { Typography, makeStyles } from "@material-ui/core"; import { Theme, Typography } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import SuccessIcon from "@components/SuccessIcon"; import SuccessIcon from "@components/SuccessIcon";
const Authenticated = function () { const Authenticated = function () {
const classes = useStyles(); const styles = useStyles();
const { t: translate } = useTranslation(); const { t: translate } = useTranslation();
return ( return (
<div id="authenticated-stage"> <div id="authenticated-stage">
<div className={classes.iconContainer}> <div className={styles.iconContainer}>
<SuccessIcon /> <SuccessIcon />
</div> </div>
<Typography>{translate("Authenticated")}</Typography> <Typography>{translate("Authenticated")}</Typography>
@ -20,7 +21,7 @@ const Authenticated = function () {
export default Authenticated; export default Authenticated;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
iconContainer: { iconContainer: {
marginBottom: theme.spacing(2), marginBottom: theme.spacing(2),
flex: "0 0 100%", flex: "0 0 100%",

View File

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import { Grid, makeStyles, Button } from "@material-ui/core"; import { Grid, Button, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -13,7 +14,7 @@ export interface Props {
} }
const AuthenticatedView = function (props: Props) { const AuthenticatedView = function (props: Props) {
const style = useStyles(); const styles = useStyles();
const navigate = useNavigate(); const navigate = useNavigate();
const { t: translate } = useTranslation(); const { t: translate } = useTranslation();
@ -29,7 +30,7 @@ const AuthenticatedView = function (props: Props) {
{translate("Logout")} {translate("Logout")}
</Button> </Button>
</Grid> </Grid>
<Grid item xs={12} className={style.mainContainer}> <Grid item xs={12} className={styles.mainContainer}>
<Authenticated /> <Authenticated />
</Grid> </Grid>
</Grid> </Grid>
@ -39,7 +40,7 @@ const AuthenticatedView = function (props: Props) {
export default AuthenticatedView; export default AuthenticatedView;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
mainContainer: { mainContainer: {
border: "1px solid #d6d6d6", border: "1px solid #d6d6d6",
borderRadius: "10px", borderRadius: "10px",

View File

@ -1,5 +1,6 @@
import React, { useEffect, Fragment, ReactNode, useState } from "react"; import React, { useEffect, Fragment, ReactNode, useState } from "react";
import { AccountBox, CheckBox, Contacts, Drafts, Group } from "@mui/icons-material";
import { import {
Button, Button,
Grid, Grid,
@ -9,11 +10,11 @@ import {
ListItemText, ListItemText,
Tooltip, Tooltip,
Typography, Typography,
makeStyles,
Checkbox, Checkbox,
FormControlLabel, FormControlLabel,
} from "@material-ui/core"; Theme,
import { AccountBox, CheckBox, Contacts, Drafts, Group } from "@material-ui/icons"; } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -44,7 +45,7 @@ function scopeNameToAvatar(id: string) {
} }
const ConsentView = function (props: Props) { const ConsentView = function (props: Props) {
const classes = useStyles(); const styles = useStyles();
const navigate = useNavigate(); const navigate = useNavigate();
const redirect = useRedirector(); const redirect = useRedirector();
const { createErrorNotification, resetNotification } = useNotifications(); const { createErrorNotification, resetNotification } = useNotifications();
@ -137,7 +138,7 @@ const ConsentView = function (props: Props) {
"Client ID: " + resp?.client_id "Client ID: " + resp?.client_id
} }
> >
<Typography className={classes.clientDescription}> <Typography className={styles.clientDescription}>
{resp !== undefined && resp.client_description !== "" {resp !== undefined && resp.client_description !== ""
? resp.client_description ? resp.client_description
: resp?.client_id} : resp?.client_id}
@ -149,8 +150,8 @@ const ConsentView = function (props: Props) {
<div>{translate("The above application is requesting the following permissions")}:</div> <div>{translate("The above application is requesting the following permissions")}:</div>
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
<div className={classes.scopesListContainer}> <div className={styles.scopesListContainer}>
<List className={classes.scopesList}> <List className={styles.scopesList}>
{resp?.scopes.map((scope: string) => ( {resp?.scopes.map((scope: string) => (
<Tooltip title={"Scope " + scope}> <Tooltip title={"Scope " + scope}>
<ListItem id={"scope-" + scope} dense> <ListItem id={"scope-" + scope} dense>
@ -180,7 +181,7 @@ const ConsentView = function (props: Props) {
color="primary" color="primary"
/> />
} }
className={classes.preConfigure} className={styles.preConfigure}
label={translate("Remember Consent")} label={translate("Remember Consent")}
/> />
</Tooltip> </Tooltip>
@ -191,7 +192,7 @@ const ConsentView = function (props: Props) {
<Grid item xs={6}> <Grid item xs={6}>
<Button <Button
id="accept-button" id="accept-button"
className={classes.button} className={styles.button}
disabled={!resp} disabled={!resp}
onClick={handleAcceptConsent} onClick={handleAcceptConsent}
color="primary" color="primary"
@ -203,7 +204,7 @@ const ConsentView = function (props: Props) {
<Grid item xs={6}> <Grid item xs={6}>
<Button <Button
id="deny-button" id="deny-button"
className={classes.button} className={styles.button}
disabled={!resp} disabled={!resp}
onClick={handleRejectConsent} onClick={handleRejectConsent}
color="secondary" color="secondary"
@ -220,7 +221,7 @@ const ConsentView = function (props: Props) {
); );
}; };
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
container: { container: {
paddingTop: theme.spacing(4), paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4), paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React, { MutableRefObject, useEffect, useRef, useState } from "react"; import React, { MutableRefObject, useEffect, useRef, useState } from "react";
import { makeStyles, Grid, Button, FormControlLabel, Checkbox, Link } from "@material-ui/core"; import { Grid, Button, FormControlLabel, Checkbox, Link, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames"; import classnames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -29,7 +30,7 @@ export interface Props {
} }
const FirstFactorForm = function (props: Props) { const FirstFactorForm = function (props: Props) {
const style = useStyles(); const styles = useStyles();
const navigate = useNavigate(); const navigate = useNavigate();
const redirectionURL = useRedirectionURL(); const redirectionURL = useRedirectionURL();
const requestMethod = useRequestMethod(); const requestMethod = useRequestMethod();
@ -170,7 +171,7 @@ const FirstFactorForm = function (props: Props) {
/> />
</Grid> </Grid>
{props.rememberMe ? ( {props.rememberMe ? (
<Grid item xs={12} className={classnames(style.actionRow)}> <Grid item xs={12} className={classnames(styles.actionRow)}>
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox
@ -192,7 +193,7 @@ const FirstFactorForm = function (props: Props) {
color="primary" color="primary"
/> />
} }
className={style.rememberMe} className={styles.rememberMe}
label={translate("Remember me")} label={translate("Remember me")}
/> />
</Grid> </Grid>
@ -210,12 +211,13 @@ const FirstFactorForm = function (props: Props) {
</Button> </Button>
</Grid> </Grid>
{props.resetPassword ? ( {props.resetPassword ? (
<Grid item xs={12} className={classnames(style.actionRow, style.flexEnd)}> <Grid item xs={12} className={classnames(styles.actionRow, styles.flexEnd)}>
<Link <Link
id="reset-password-button" id="reset-password-button"
component="button" component="button"
onClick={handleResetPasswordClick} onClick={handleResetPasswordClick}
className={style.resetLink} className={styles.resetLink}
underline="hover"
> >
{translate("Reset password?")} {translate("Reset password?")}
</Link> </Link>
@ -228,7 +230,7 @@ const FirstFactorForm = function (props: Props) {
export default FirstFactorForm; export default FirstFactorForm;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
actionRow: { actionRow: {
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "row",

View File

@ -1,6 +1,7 @@
import React, { ReactNode, useState } from "react"; import React, { ReactNode, useState } from "react";
import { makeStyles, Typography, Grid, Button, Container } from "@material-ui/core"; import { Typography, Grid, Button, Container, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import PushNotificationIcon from "@components/PushNotificationIcon"; import PushNotificationIcon from "@components/PushNotificationIcon";
@ -102,7 +103,7 @@ interface DeviceItemProps {
function DeviceItem(props: DeviceItemProps) { function DeviceItem(props: DeviceItemProps) {
const className = "device-option-" + props.id; const className = "device-option-" + props.id;
const idName = "device-" + props.device.id; const idName = "device-" + props.device.id;
const style = makeStyles((theme) => ({ const style = makeStyles((theme: Theme) => ({
item: { item: {
paddingTop: theme.spacing(4), paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4), paddingBottom: theme.spacing(4),
@ -147,7 +148,7 @@ interface MethodItemProps {
function MethodItem(props: MethodItemProps) { function MethodItem(props: MethodItemProps) {
const className = "method-option-" + props.id; const className = "method-option-" + props.id;
const idName = "method-" + props.method; const idName = "method-" + props.method;
const style = makeStyles((theme) => ({ const style = makeStyles((theme: Theme) => ({
item: { item: {
paddingTop: theme.spacing(4), paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4), paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React, { ReactNode } from "react"; import React, { ReactNode } from "react";
import { makeStyles } from "@material-ui/core"; import { Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames"; import classnames from "classnames";
interface IconWithContextProps { interface IconWithContextProps {
@ -12,7 +13,7 @@ interface IconWithContextProps {
const IconWithContext = function (props: IconWithContextProps) { const IconWithContext = function (props: IconWithContextProps) {
const iconSize = 64; const iconSize = 64;
const style = makeStyles((theme) => ({ const styles = makeStyles((theme: Theme) => ({
root: {}, root: {},
iconContainer: { iconContainer: {
display: "flex", display: "flex",
@ -29,11 +30,11 @@ const IconWithContext = function (props: IconWithContextProps) {
}))(); }))();
return ( return (
<div className={classnames(props.className, style.root)}> <div className={classnames(props.className, styles.root)}>
<div className={style.iconContainer}> <div className={styles.iconContainer}>
<div className={style.icon}>{props.icon}</div> <div className={styles.icon}>{props.icon}</div>
</div> </div>
<div className={style.context}>{props.children}</div> <div className={styles.context}>{props.children}</div>
</div> </div>
); );
}; };

View File

@ -1,6 +1,7 @@
import React, { ReactNode, Fragment } from "react"; import React, { ReactNode, Fragment } from "react";
import { makeStyles, Typography, Link, useTheme } from "@material-ui/core"; import { Typography, Link, Theme, Box } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames"; import classnames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -27,7 +28,7 @@ export interface Props {
} }
const DefaultMethodContainer = function (props: Props) { const DefaultMethodContainer = function (props: Props) {
const style = useStyles(); const styles = useStyles();
const { t: translate } = useTranslation(); const { t: translate } = useTranslation();
const registerMessage = props.registered const registerMessage = props.registered
? props.title === "Push Notification" ? props.title === "Push Notification"
@ -56,17 +57,17 @@ const DefaultMethodContainer = function (props: Props) {
return ( return (
<div id={props.id}> <div id={props.id}>
<Typography variant="h6">{props.title}</Typography> <Typography variant="h6">{props.title}</Typography>
<div className={classnames(style.container, stateClass)} id="2fa-container"> <div className={classnames(styles.container, stateClass)} id="2fa-container">
<div className={style.containerFlex}>{container}</div> <div className={styles.containerFlex}>{container}</div>
</div> </div>
{props.onSelectClick && props.registered ? ( {props.onSelectClick && props.registered ? (
<Link component="button" id="selection-link" onClick={props.onSelectClick}> <Link component="button" id="selection-link" onClick={props.onSelectClick} underline="hover">
{selectMessage} {selectMessage}
</Link> </Link>
) : null} ) : null}
{(props.onRegisterClick && props.title !== "Push Notification") || {(props.onRegisterClick && props.title !== "Push Notification") ||
(props.onRegisterClick && props.title === "Push Notification" && props.duoSelfEnrollment) ? ( (props.onRegisterClick && props.title === "Push Notification" && props.duoSelfEnrollment) ? (
<Link component="button" id="register-link" onClick={props.onRegisterClick}> <Link component="button" id="register-link" onClick={props.onRegisterClick} underline="hover">
{registerMessage} {registerMessage}
</Link> </Link>
) : null} ) : null}
@ -76,7 +77,7 @@ const DefaultMethodContainer = function (props: Props) {
export default DefaultMethodContainer; export default DefaultMethodContainer;
const useStyles = makeStyles(() => ({ const useStyles = makeStyles((theme: Theme) => ({
container: { container: {
height: "200px", height: "200px",
}, },
@ -89,6 +90,16 @@ const useStyles = makeStyles(() => ({
alignContent: "center", alignContent: "center",
justifyContent: "center", justifyContent: "center",
}, },
containerMethod: {
marginBottom: theme.spacing(2),
},
info: {
marginBottom: theme.spacing(2),
flex: "0 0 100%",
},
infoTypography: {
color: "#5858ff",
},
})); }));
interface NotRegisteredContainerProps { interface NotRegisteredContainerProps {
@ -98,16 +109,17 @@ interface NotRegisteredContainerProps {
function NotRegisteredContainer(props: NotRegisteredContainerProps) { function NotRegisteredContainer(props: NotRegisteredContainerProps) {
const { t: translate } = useTranslation(); const { t: translate } = useTranslation();
const theme = useTheme(); const styles = useStyles();
return ( return (
<Fragment> <Fragment>
<div style={{ marginBottom: theme.spacing(2), flex: "0 0 100%" }}> <Box className={styles.info}>
<InformationIcon /> <InformationIcon />
</div> </Box>
<Typography style={{ color: "#5858ff" }}> <Typography className={styles.infoTypography}>
{translate("The resource you're attempting to access requires two-factor authentication")} {translate("The resource you're attempting to access requires two-factor authentication")}
</Typography> </Typography>
<Typography style={{ color: "#5858ff" }}> <Typography className={styles.infoTypography}>
{props.title === "Push Notification" {props.title === "Push Notification"
? props.duoSelfEnrollment ? props.duoSelfEnrollment
? translate("Register your first device by clicking on the link below") ? translate("Register your first device by clicking on the link below")
@ -124,10 +136,11 @@ interface MethodContainerProps {
} }
function MethodContainer(props: MethodContainerProps) { function MethodContainer(props: MethodContainerProps) {
const theme = useTheme(); const styles = useStyles();
return ( return (
<Fragment> <Fragment>
<div style={{ marginBottom: theme.spacing(2) }}>{props.children}</div> <Box className={styles.containerMethod}>{props.children}</Box>
<Typography>{props.explanation}</Typography> <Typography>{props.explanation}</Typography>
</Fragment> </Fragment>
); );

View File

@ -1,15 +1,7 @@
import React, { ReactNode } from "react"; import React, { ReactNode } from "react";
import { import { Dialog, Grid, DialogContent, Button, DialogActions, Typography, useTheme, Theme } from "@mui/material";
Dialog, import makeStyles from "@mui/styles/makeStyles";
Grid,
makeStyles,
DialogContent,
Button,
DialogActions,
Typography,
useTheme,
} from "@material-ui/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import FingerTouchIcon from "@components/FingerTouchIcon"; import FingerTouchIcon from "@components/FingerTouchIcon";
@ -27,7 +19,7 @@ export interface Props {
} }
const MethodSelectionDialog = function (props: Props) { const MethodSelectionDialog = function (props: Props) {
const style = useStyles(); const styles = useStyles();
const theme = useTheme(); const theme = useTheme();
const { t: translate } = useTranslation(); const { t: translate } = useTranslation();
@ -36,7 +28,7 @@ const MethodSelectionDialog = function (props: Props) {
); );
return ( return (
<Dialog open={props.open} className={style.root} onClose={props.onClose}> <Dialog open={props.open} className={styles.root} onClose={props.onClose}>
<DialogContent> <DialogContent>
<Grid container justifyContent="center" spacing={1} id="methods-dialog"> <Grid container justifyContent="center" spacing={1} id="methods-dialog">
{props.methods.has(SecondFactorMethod.TOTP) ? ( {props.methods.has(SecondFactorMethod.TOTP) ? (
@ -76,7 +68,7 @@ const MethodSelectionDialog = function (props: Props) {
export default MethodSelectionDialog; export default MethodSelectionDialog;
const useStyles = makeStyles(() => ({ const useStyles = makeStyles((theme: Theme) => ({
root: { root: {
textAlign: "center", textAlign: "center",
}, },
@ -91,7 +83,7 @@ interface MethodItemProps {
} }
function MethodItem(props: MethodItemProps) { function MethodItem(props: MethodItemProps) {
const style = makeStyles((theme) => ({ const style = makeStyles((theme: Theme) => ({
item: { item: {
paddingTop: theme.spacing(4), paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4), paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React, { Fragment } from "react"; import React, { Fragment } from "react";
import { makeStyles } from "@material-ui/core"; import { Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames"; import classnames from "classnames";
import OtpInput from "react-otp-input"; import OtpInput from "react-otp-input";
@ -20,11 +21,11 @@ export interface Props {
} }
const OTPDial = function (props: Props) { const OTPDial = function (props: Props) {
const style = useStyles(); const styles = useStyles();
return ( return (
<IconWithContext icon={<Icon state={props.state} period={props.period} />}> <IconWithContext icon={<Icon state={props.state} period={props.period} />}>
<span className={style.otpInput} id="otp-input"> <span className={styles.otpInput} id="otp-input">
<OtpInput <OtpInput
shouldAutoFocus shouldAutoFocus
onChange={props.onChange} onChange={props.onChange}
@ -33,7 +34,10 @@ const OTPDial = function (props: Props) {
isDisabled={props.state === State.InProgress || props.state === State.Success} isDisabled={props.state === State.InProgress || props.state === State.Success}
isInputNum isInputNum
hasErrored={props.state === State.Failure} hasErrored={props.state === State.Failure}
inputStyle={classnames(style.otpDigitInput, props.state === State.Failure ? style.inputError : "")} inputStyle={classnames(
styles.otpDigitInput,
props.state === State.Failure ? styles.inputError : "",
)}
/> />
</span> </span>
</IconWithContext> </IconWithContext>
@ -42,7 +46,7 @@ const OTPDial = function (props: Props) {
export default OTPDial; export default OTPDial;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
timeProgress: {}, timeProgress: {},
register: { register: {
marginTop: theme.spacing(), marginTop: theme.spacing(),

View File

@ -1,6 +1,7 @@
import React, { useEffect, useCallback, useRef, useState, ReactNode } from "react"; import React, { useEffect, useCallback, useRef, useState, ReactNode } from "react";
import { Button, makeStyles } from "@material-ui/core"; import { Button, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import FailureIcon from "@components/FailureIcon"; import FailureIcon from "@components/FailureIcon";
import PushNotificationIcon from "@components/PushNotificationIcon"; import PushNotificationIcon from "@components/PushNotificationIcon";
@ -40,7 +41,7 @@ export interface Props {
} }
const PushNotificationMethod = function (props: Props) { const PushNotificationMethod = function (props: Props) {
const style = useStyles(); const styles = useStyles();
const [state, setState] = useState(State.SignInInProgress); const [state, setState] = useState(State.SignInInProgress);
const redirectionURL = useRedirectionURL(); const redirectionURL = useRedirectionURL();
const mounted = useIsMountedRef(); const mounted = useIsMountedRef();
@ -216,7 +217,7 @@ const PushNotificationMethod = function (props: Props) {
onSelectClick={fetchDuoDevicesFunc} onSelectClick={fetchDuoDevicesFunc}
onRegisterClick={() => window.open(enroll_url, "_blank")} onRegisterClick={() => window.open(enroll_url, "_blank")}
> >
<div className={style.icon}>{icon}</div> <div className={styles.icon}>{icon}</div>
<div className={state !== State.Failure ? "hidden" : ""}> <div className={state !== State.Failure ? "hidden" : ""}>
<Button color="secondary" onClick={signInFunc}> <Button color="secondary" onClick={signInFunc}>
Retry Retry
@ -228,7 +229,7 @@ const PushNotificationMethod = function (props: Props) {
export default PushNotificationMethod; export default PushNotificationMethod;
const useStyles = makeStyles(() => ({ const useStyles = makeStyles((theme: Theme) => ({
icon: { icon: {
width: "64px", width: "64px",
height: "64px", height: "64px",

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Grid, makeStyles, Button } from "@material-ui/core"; import { Grid, Button, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Route, Routes, useNavigate } from "react-router-dom"; import { Route, Routes, useNavigate } from "react-router-dom";
@ -35,7 +36,7 @@ export interface Props {
} }
const SecondFactorForm = function (props: Props) { const SecondFactorForm = function (props: Props) {
const style = useStyles(); const styles = useStyles();
const navigate = useNavigate(); const navigate = useNavigate();
const [methodSelectionOpen, setMethodSelectionOpen] = useState(false); const [methodSelectionOpen, setMethodSelectionOpen] = useState(false);
const { createInfoNotification, createErrorNotification } = useNotifications(); const { createInfoNotification, createErrorNotification } = useNotifications();
@ -106,7 +107,7 @@ const SecondFactorForm = function (props: Props) {
</Button> </Button>
) : null} ) : null}
</Grid> </Grid>
<Grid item xs={12} className={style.methodContainer}> <Grid item xs={12} className={styles.methodContainer}>
<Routes> <Routes>
<Route <Route
path={SecondFactorTOTPSubRoute} path={SecondFactorTOTPSubRoute}
@ -159,7 +160,7 @@ const SecondFactorForm = function (props: Props) {
export default SecondFactorForm; export default SecondFactorForm;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
methodContainer: { methodContainer: {
border: "1px solid #d6d6d6", border: "1px solid #d6d6d6",
borderRadius: "10px", borderRadius: "10px",

View File

@ -1,7 +1,7 @@
import React, { Fragment, useCallback, useEffect, useRef, useState } from "react"; import React, { Fragment, useCallback, useEffect, useRef, useState } from "react";
import { Button, makeStyles, useTheme } from "@material-ui/core"; import { Button, Theme, useTheme } from "@mui/material";
import { CSSProperties } from "@material-ui/styles"; import makeStyles from "@mui/styles/makeStyles";
import FailureIcon from "@components/FailureIcon"; import FailureIcon from "@components/FailureIcon";
import FingerTouchIcon from "@components/FingerTouchIcon"; import FingerTouchIcon from "@components/FingerTouchIcon";
@ -38,7 +38,7 @@ export interface Props {
const WebauthnMethod = function (props: Props) { const WebauthnMethod = function (props: Props) {
const signInTimeout = 30; const signInTimeout = 30;
const [state, setState] = useState(State.WaitTouch); const [state, setState] = useState(State.WaitTouch);
const style = useStyles(); const styles = useStyles();
const redirectionURL = useRedirectionURL(); const redirectionURL = useRedirectionURL();
const mounted = useIsMountedRef(); const mounted = useIsMountedRef();
const [timerPercent, triggerTimer] = useTimer(signInTimeout * 1000 - 500); const [timerPercent, triggerTimer] = useTimer(signInTimeout * 1000 - 500);
@ -162,7 +162,7 @@ const WebauthnMethod = function (props: Props) {
state={methodState} state={methodState}
onRegisterClick={props.onRegisterClick} onRegisterClick={props.onRegisterClick}
> >
<div className={style.icon}> <div className={styles.icon}>
<Icon state={state} timer={timerPercent} onRetryClick={doInitiateSignIn} /> <Icon state={state} timer={timerPercent} onRetryClick={doInitiateSignIn} />
</div> </div>
</MethodContainer> </MethodContainer>
@ -171,7 +171,7 @@ const WebauthnMethod = function (props: Props) {
export default WebauthnMethod; export default WebauthnMethod;
const useStyles = makeStyles(() => ({ const useStyles = makeStyles((theme: Theme) => ({
icon: { icon: {
display: "inline-block", display: "inline-block",
}, },
@ -188,16 +188,18 @@ function Icon(props: IconProps) {
const state = props.state as State; const state = props.state as State;
const theme = useTheme(); const theme = useTheme();
const progressBarStyle: CSSProperties = { const styles = makeStyles((theme: Theme) => ({
progressBar: {
marginTop: theme.spacing(), marginTop: theme.spacing(),
}; },
}))();
const touch = ( const touch = (
<IconWithContext <IconWithContext
icon={<FingerTouchIcon size={64} animated strong />} icon={<FingerTouchIcon size={64} animated strong />}
className={state === State.WaitTouch ? undefined : "hidden"} className={state === State.WaitTouch ? undefined : "hidden"}
> >
<LinearProgressBar value={props.timer} style={progressBarStyle} height={theme.spacing(2)} /> <LinearProgressBar value={props.timer} className={styles.progressBar} height={theme.spacing(2)} />
</IconWithContext> </IconWithContext>
); );

View File

@ -1,6 +1,7 @@
import React, { useEffect, useCallback, useState } from "react"; import React, { useEffect, useCallback, useState } from "react";
import { Typography, makeStyles } from "@material-ui/core"; import { Theme, Typography } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Navigate } from "react-router-dom"; import { Navigate } from "react-router-dom";
@ -16,7 +17,7 @@ export interface Props {}
const SignOut = function (props: Props) { const SignOut = function (props: Props) {
const mounted = useIsMountedRef(); const mounted = useIsMountedRef();
const style = useStyles(); const styles = useStyles();
const { createErrorNotification } = useNotifications(); const { createErrorNotification } = useNotifications();
const redirectionURL = useRedirectionURL(); const redirectionURL = useRedirectionURL();
const redirector = useRedirector(); const redirector = useRedirector();
@ -56,14 +57,14 @@ const SignOut = function (props: Props) {
return ( return (
<LoginLayout title={translate("Sign out")}> <LoginLayout title={translate("Sign out")}>
<Typography className={style.typo}>{translate("You're being signed out and redirected")}...</Typography> <Typography className={styles.typo}>{translate("You're being signed out and redirected")}...</Typography>
</LoginLayout> </LoginLayout>
); );
}; };
export default SignOut; export default SignOut;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
typo: { typo: {
padding: theme.spacing(), padding: theme.spacing(),
}, },

View File

@ -1,6 +1,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Grid, Button, makeStyles } from "@material-ui/core"; import { Grid, Button, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -11,7 +12,7 @@ import LoginLayout from "@layouts/LoginLayout";
import { initiateResetPasswordProcess } from "@services/ResetPassword"; import { initiateResetPasswordProcess } from "@services/ResetPassword";
const ResetPasswordStep1 = function () { const ResetPasswordStep1 = function () {
const style = useStyles(); const styles = useStyles();
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [error, setError] = useState(false); const [error, setError] = useState(false);
const { createInfoNotification, createErrorNotification } = useNotifications(); const { createInfoNotification, createErrorNotification } = useNotifications();
@ -42,7 +43,7 @@ const ResetPasswordStep1 = function () {
return ( return (
<LoginLayout title={translate("Reset password")} id="reset-password-step1-stage"> <LoginLayout title={translate("Reset password")} id="reset-password-step1-stage">
<Grid container className={style.root} spacing={2}> <Grid container className={styles.root} spacing={2}>
<Grid item xs={12}> <Grid item xs={12}>
<FixedTextField <FixedTextField
id="username-textfield" id="username-textfield"
@ -83,7 +84,7 @@ const ResetPasswordStep1 = function () {
export default ResetPasswordStep1; export default ResetPasswordStep1;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
root: { root: {
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
marginBottom: theme.spacing(2), marginBottom: theme.spacing(2),

View File

@ -1,7 +1,8 @@
import React, { useCallback, useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { Button, Grid, IconButton, InputAdornment, makeStyles } from "@material-ui/core"; import { Visibility, VisibilityOff } from "@mui/icons-material";
import { Visibility, VisibilityOff } from "@material-ui/icons"; import { Button, Grid, IconButton, InputAdornment, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames"; import classnames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
@ -17,7 +18,7 @@ import { completeResetPasswordProcess, resetPassword } from "@services/ResetPass
import { extractIdentityToken } from "@utils/IdentityToken"; import { extractIdentityToken } from "@utils/IdentityToken";
const ResetPasswordStep2 = function () { const ResetPasswordStep2 = function () {
const style = useStyles(); const styles = useStyles();
const location = useLocation(); const location = useLocation();
const [formDisabled, setFormDisabled] = useState(true); const [formDisabled, setFormDisabled] = useState(true);
const [password1, setPassword1] = useState(""); const [password1, setPassword1] = useState("");
@ -110,7 +111,7 @@ const ResetPasswordStep2 = function () {
return ( return (
<LoginLayout title={translate("Enter new password")} id="reset-password-step2-stage"> <LoginLayout title={translate("Enter new password")} id="reset-password-step2-stage">
<Grid container className={style.root} spacing={2}> <Grid container className={styles.root} spacing={2}>
<Grid item xs={12}> <Grid item xs={12}>
<FixedTextField <FixedTextField
id="password1-textfield" id="password1-textfield"
@ -121,7 +122,7 @@ const ResetPasswordStep2 = function () {
disabled={formDisabled} disabled={formDisabled}
onChange={(e) => setPassword1(e.target.value)} onChange={(e) => setPassword1(e.target.value)}
error={errorPassword1} error={errorPassword1}
className={classnames(style.fullWidth)} className={classnames(styles.fullWidth)}
autoComplete="new-password" autoComplete="new-password"
InputProps={{ InputProps={{
endAdornment: ( endAdornment: (
@ -130,6 +131,7 @@ const ResetPasswordStep2 = function () {
aria-label="toggle password visibility" aria-label="toggle password visibility"
onClick={(e) => setShowPassword(!showPassword)} onClick={(e) => setShowPassword(!showPassword)}
edge="end" edge="end"
size="large"
> >
{showPassword ? <VisibilityOff></VisibilityOff> : <Visibility></Visibility>} {showPassword ? <VisibilityOff></VisibilityOff> : <Visibility></Visibility>}
</IconButton> </IconButton>
@ -157,7 +159,7 @@ const ResetPasswordStep2 = function () {
ev.preventDefault(); ev.preventDefault();
} }
}} }}
className={classnames(style.fullWidth)} className={classnames(styles.fullWidth)}
autoComplete="new-password" autoComplete="new-password"
/> />
</Grid> </Grid>
@ -169,7 +171,7 @@ const ResetPasswordStep2 = function () {
name="password1" name="password1"
disabled={formDisabled} disabled={formDisabled}
onClick={handleResetClick} onClick={handleResetClick}
className={style.fullWidth} className={styles.fullWidth}
> >
{translate("Reset")} {translate("Reset")}
</Button> </Button>
@ -181,7 +183,7 @@ const ResetPasswordStep2 = function () {
color="primary" color="primary"
name="password2" name="password2"
onClick={handleCancelClick} onClick={handleCancelClick}
className={style.fullWidth} className={styles.fullWidth}
> >
{translate("Cancel")} {translate("Cancel")}
</Button> </Button>
@ -193,7 +195,7 @@ const ResetPasswordStep2 = function () {
export default ResetPasswordStep2; export default ResetPasswordStep2;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme: Theme) => ({
root: { root: {
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
marginBottom: theme.spacing(2), marginBottom: theme.spacing(2),