mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
Fix/standalone pages (#300)
* feat: change layout * fix: standalone banner styling * fix: change styling for banner * fix: login page * fix: standalone pages * fix: page tweaks * fix: center text * refactor: new user page * refactor: remove uneccesary markup * refactor: remove secondary actions from hosted * fix: remove authdetails blob * refactor: remove unused import * fix: move overflow * fix: add breakpoint to forgotten password
This commit is contained in:
parent
998cdf98ab
commit
bd93c5d131
@ -60,6 +60,7 @@
|
||||
>
|
||||
<g
|
||||
id="button"
|
||||
|
||||
transform="translate(4.000000, 4.000000)"
|
||||
filter="url(#filter-1)"
|
||||
>
|
||||
@ -74,22 +75,22 @@
|
||||
<path
|
||||
d="M17.64,9.20454545 C17.64,8.56636364 17.5827273,7.95272727 17.4763636,7.36363636 L9,7.36363636 L9,10.845 L13.8436364,10.845 C13.635,11.97 13.0009091,12.9231818 12.0477273,13.5613636 L12.0477273,15.8195455 L14.9563636,15.8195455 C16.6581818,14.2527273 17.64,11.9454545 17.64,9.20454545 L17.64,9.20454545 Z"
|
||||
id="Shape"
|
||||
fill="#4285F4"
|
||||
fill="#000"
|
||||
/>
|
||||
<path
|
||||
d="M9,18 C11.43,18 13.4672727,17.1940909 14.9563636,15.8195455 L12.0477273,13.5613636 C11.2418182,14.1013636 10.2109091,14.4204545 9,14.4204545 C6.65590909,14.4204545 4.67181818,12.8372727 3.96409091,10.71 L0.957272727,10.71 L0.957272727,13.0418182 C2.43818182,15.9831818 5.48181818,18 9,18 L9,18 Z"
|
||||
id="Shape"
|
||||
fill="#34A853"
|
||||
fill="#000"
|
||||
/>
|
||||
<path
|
||||
d="M3.96409091,10.71 C3.78409091,10.17 3.68181818,9.59318182 3.68181818,9 C3.68181818,8.40681818 3.78409091,7.83 3.96409091,7.29 L3.96409091,4.95818182 L0.957272727,4.95818182 C0.347727273,6.17318182 0,7.54772727 0,9 C0,10.4522727 0.347727273,11.8268182 0.957272727,13.0418182 L3.96409091,10.71 L3.96409091,10.71 Z"
|
||||
id="Shape"
|
||||
fill="#FBBC05"
|
||||
fill="#000"
|
||||
/>
|
||||
<path
|
||||
d="M9,3.57954545 C10.3213636,3.57954545 11.5077273,4.03363636 12.4404545,4.92545455 L15.0218182,2.34409091 C13.4631818,0.891818182 11.4259091,0 9,0 C5.48181818,0 2.43818182,2.01681818 0.957272727,4.95818182 L3.96409091,7.29 C4.67181818,5.16272727 6.65590909,3.57954545 9,3.57954545 L9,3.57954545 Z"
|
||||
id="Shape"
|
||||
fill="#EA4335"
|
||||
fill="#000"
|
||||
/>
|
||||
<path d="M0,0 L18,0 L18,18 L0,18 L0,0 Z" id="Shape" />
|
||||
</g>
|
||||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
7
frontend/src/assets/img/logo.svg
Normal file
7
frontend/src/assets/img/logo.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg width="52" height="52" viewBox="0 0 52 52" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="26" cy="26" r="26" fill="white"/>
|
||||
<rect x="15" y="15" width="7" height="22" fill="#1A4049"/>
|
||||
<rect x="30" y="15" width="7" height="22" fill="#1A4049"/>
|
||||
<path d="M37 30L37 37L15 37L15 30L37 30Z" fill="#1A4049"/>
|
||||
<rect x="30" y="30" width="7" height="7" fill="#817AFE"/>
|
||||
</svg>
|
After Width: | Height: | Size: 384 B |
@ -0,0 +1,21 @@
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
|
||||
export const useStyles = makeStyles(theme => ({
|
||||
container: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
margin: '1rem auto',
|
||||
},
|
||||
wing: {
|
||||
width: '80px',
|
||||
height: '3px',
|
||||
backgroundColor: theme.palette.division.main,
|
||||
borderRadius: theme.borders.radius.main,
|
||||
},
|
||||
text: {
|
||||
textAlign: 'center',
|
||||
display: 'block',
|
||||
margin: '0 1rem',
|
||||
},
|
||||
}));
|
22
frontend/src/component/common/DividerText/DividerText.tsx
Normal file
22
frontend/src/component/common/DividerText/DividerText.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { useStyles } from './DividerText.styles';
|
||||
|
||||
interface IDividerTextProps {
|
||||
text: string;
|
||||
}
|
||||
|
||||
const DividerText = ({ text, ...rest }: IDividerTextProps) => {
|
||||
const styles = useStyles();
|
||||
|
||||
return (
|
||||
<div className={styles.container} {...rest}>
|
||||
<span className={styles.wing} />
|
||||
<Typography variant="body2" className={styles.text}>
|
||||
{text}
|
||||
</Typography>
|
||||
<span className={styles.wing} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DividerText;
|
@ -1,12 +1,14 @@
|
||||
interface IGradientProps {
|
||||
from: string;
|
||||
to: string;
|
||||
style?: object;
|
||||
}
|
||||
|
||||
const Gradient: React.FC<IGradientProps> = ({
|
||||
children,
|
||||
from,
|
||||
to,
|
||||
style,
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
@ -15,6 +17,8 @@ const Gradient: React.FC<IGradientProps> = ({
|
||||
background: `linear-gradient(${from}, ${to})`,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
...style,
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
|
@ -4,7 +4,7 @@ import { Button, TextField } from '@material-ui/core';
|
||||
|
||||
import styles from './DemoAuth.module.scss';
|
||||
|
||||
import logoIcon from '../../../assets/img/logo.png';
|
||||
import { ReactComponent as Logo } from '../../../assets/img/logo.svg';
|
||||
|
||||
const DemoAuth = ({ demoLogin, history, authDetails }) => {
|
||||
const [email, setEmail] = useState('');
|
||||
@ -24,13 +24,14 @@ const DemoAuth = ({ demoLogin, history, authDetails }) => {
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} action={authDetails.path}>
|
||||
<Logo className={styles.logo} />
|
||||
<div className={styles.container}>
|
||||
<img alt="Unleash Logo" src={logoIcon} width="70" height="70" />
|
||||
<h2>Access the Unleash demo instance</h2>
|
||||
<p>No further data or Credit Card required</p>
|
||||
<div className={styles.form}>
|
||||
<TextField
|
||||
value={email}
|
||||
className={styles.emailField}
|
||||
onChange={handleChange}
|
||||
inputProps={{ 'data-test': 'email-input-field' }}
|
||||
size="small"
|
||||
@ -40,7 +41,7 @@ const DemoAuth = ({ demoLogin, history, authDetails }) => {
|
||||
required
|
||||
type="email"
|
||||
/>
|
||||
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
|
@ -1,11 +1,34 @@
|
||||
.container {
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
margin: 0.6rem 0;
|
||||
}
|
||||
|
||||
.button {
|
||||
min-width: 150px;
|
||||
.emailField {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form {
|
||||
margin: 4em 1em
|
||||
.form > * {
|
||||
margin: 0.6rem 0;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.button {
|
||||
min-width: 150px;
|
||||
margin: 1rem auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,21 @@
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
export const useStyles = makeStyles({
|
||||
container: {
|
||||
maxWidth: '300px',
|
||||
export const useStyles = makeStyles(theme => ({
|
||||
forgottenPassword: {
|
||||
width: '350px',
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
button: {
|
||||
width: '150px',
|
||||
margin: '1rem auto',
|
||||
},
|
||||
email: {
|
||||
display: 'block',
|
||||
margin: '0.5rem 0',
|
||||
},
|
||||
});
|
||||
loginText: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
}));
|
||||
|
@ -2,10 +2,12 @@ import { Button, TextField, Typography } from '@material-ui/core';
|
||||
import { AlertTitle, Alert } from '@material-ui/lab';
|
||||
import classnames from 'classnames';
|
||||
import { SyntheticEvent, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useCommonStyles } from '../../../common.styles';
|
||||
import useLoading from '../../../hooks/useLoading';
|
||||
import { formatApiPath } from '../../../utils/format-path';
|
||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||
import DividerText from '../../common/DividerText/DividerText';
|
||||
import StandaloneLayout from '../common/StandaloneLayout/StandaloneLayout';
|
||||
import { useStyles } from './ForgottenPassword.styles';
|
||||
|
||||
@ -41,7 +43,8 @@ const ForgottenPassword = () => {
|
||||
<div
|
||||
className={classnames(
|
||||
commonStyles.contentSpacingY,
|
||||
commonStyles.flexColumn
|
||||
commonStyles.flexColumn,
|
||||
styles.forgottenPassword
|
||||
)}
|
||||
ref={ref}
|
||||
>
|
||||
@ -105,6 +108,18 @@ const ForgottenPassword = () => {
|
||||
elseShow={<span>Try again</span>}
|
||||
/>
|
||||
</Button>
|
||||
<DividerText text="Or log in" />
|
||||
<Button
|
||||
type="submit"
|
||||
data-loading
|
||||
variant="outlined"
|
||||
className={styles.button}
|
||||
disabled={loading}
|
||||
component={Link}
|
||||
to="/login"
|
||||
>
|
||||
Log in
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</StandaloneLayout>
|
||||
|
@ -5,11 +5,12 @@ import { Button, Grid, TextField, Typography } from '@material-ui/core';
|
||||
import { useHistory } from 'react-router';
|
||||
import { useCommonStyles } from '../../../common.styles';
|
||||
import { useStyles } from './HostedAuth.styles';
|
||||
import { Link } from 'react-router-dom';
|
||||
import useQueryParams from '../../../hooks/useQueryParams';
|
||||
import AuthOptions from '../common/AuthOptions/AuthOptions';
|
||||
import DividerText from '../../common/DividerText/DividerText';
|
||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||
|
||||
const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
||||
const HostedAuth = ({ authDetails, passwordLogin }) => {
|
||||
const commonStyles = useCommonStyles();
|
||||
const styles = useStyles();
|
||||
const history = useHistory();
|
||||
@ -67,12 +68,17 @@ const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
||||
const { options = [] } = authDetails;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<br />
|
||||
<div>
|
||||
<>
|
||||
<ConditionallyRender
|
||||
condition={options.length > 0}
|
||||
show={
|
||||
<>
|
||||
<AuthOptions options={options} />
|
||||
</div>
|
||||
<p className={styles.fancyLine}>or</p>
|
||||
<DividerText text="or signin with username" />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<form onSubmit={handleSubmit} action={authDetails.path}>
|
||||
<Typography variant="subtitle2" className={styles.apiError}>
|
||||
{apiError}
|
||||
@ -105,43 +111,26 @@ const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
||||
variant="outlined"
|
||||
size="small"
|
||||
/>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
style={{ maxWidth: '150px' }}
|
||||
className={styles.button}
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Link to="/forgotten-password">
|
||||
<Typography variant="body2" align="right">
|
||||
Forgot your password?
|
||||
</Typography>
|
||||
</Link>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<br />
|
||||
<br />
|
||||
<Typography variant="body2" align="center">
|
||||
Don't have an account? <br />{' '}
|
||||
<a href="https://www.unleash-hosted.com/pricing">
|
||||
Sign up
|
||||
</a>
|
||||
</Typography>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
PasswordAuth.propTypes = {
|
||||
HostedAuth.propTypes = {
|
||||
authDetails: PropTypes.object.isRequired,
|
||||
passwordLogin: PropTypes.func.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default PasswordAuth;
|
||||
export default HostedAuth;
|
||||
|
@ -15,26 +15,10 @@ export const useStyles = makeStyles(theme => ({
|
||||
apiError: {
|
||||
color: theme.palette.error.main,
|
||||
},
|
||||
|
||||
fancyLine: {
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
margin: '10px 0',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
button: {
|
||||
width: '150px',
|
||||
margin: '1rem auto 0 auto',
|
||||
display: 'block',
|
||||
textAlign: 'center',
|
||||
color: 'gray',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
borderTop: '1px solid silver',
|
||||
margin: '0 20px 0 0',
|
||||
flex: '1 0 20px',
|
||||
},
|
||||
'&::after': {
|
||||
content: '""',
|
||||
borderTop: '1px solid silver',
|
||||
margin: '0 20px 0 0',
|
||||
flex: '1 0 20px',
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
@ -7,6 +7,7 @@ import { useStyles } from './Login.styles';
|
||||
import useQueryParams from '../../../hooks/useQueryParams';
|
||||
import ResetPasswordSuccess from '../common/ResetPasswordSuccess/ResetPasswordSuccess';
|
||||
import StandaloneLayout from '../common/StandaloneLayout/StandaloneLayout';
|
||||
import { DEMO_TYPE } from '../../../constants/authTypes';
|
||||
|
||||
const Login = ({ history, user, fetchUser }) => {
|
||||
const styles = useStyles();
|
||||
@ -28,16 +29,22 @@ const Login = ({ history, user, fetchUser }) => {
|
||||
|
||||
return (
|
||||
<StandaloneLayout>
|
||||
<div>
|
||||
<h2 className={styles.title}>Login</h2>
|
||||
<div className={styles.loginFormContainer}>
|
||||
<ConditionallyRender
|
||||
condition={user?.authDetails?.type !== DEMO_TYPE}
|
||||
show={
|
||||
<h2 className={styles.title}>
|
||||
Login to continue the great work
|
||||
</h2>
|
||||
}
|
||||
/>
|
||||
|
||||
<ConditionallyRender
|
||||
condition={resetPassword}
|
||||
show={<ResetPasswordSuccess />}
|
||||
/>
|
||||
<div className={styles.loginFormContainer}>
|
||||
<AuthenticationContainer history={history} />
|
||||
</div>
|
||||
</div>
|
||||
</StandaloneLayout>
|
||||
);
|
||||
};
|
||||
|
@ -1,6 +1,13 @@
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
|
||||
export const useStyles = makeStyles(theme => ({
|
||||
login: {
|
||||
width: '350px',
|
||||
maxWidth: '350px',
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
loginContainer: {
|
||||
minHeight: '100vh',
|
||||
width: '100%',
|
||||
@ -25,7 +32,7 @@ export const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
title: {
|
||||
fontSize: theme.fontSizes.mainHeader,
|
||||
marginBottom: '0.5rem',
|
||||
marginBottom: '1rem',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
@ -38,7 +45,8 @@ export const useStyles = makeStyles(theme => ({
|
||||
fontSize: '1.25rem',
|
||||
},
|
||||
loginFormContainer: {
|
||||
maxWidth: '500px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
imageContainer: {
|
||||
display: 'flex',
|
||||
|
@ -1,6 +1,22 @@
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
export const useStyles = makeStyles(theme => ({
|
||||
newUser: {
|
||||
width: '350px',
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
title: {
|
||||
fontSize: theme.fontSizes.mainHeader,
|
||||
marginBottom: '1.25rem',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
inviteText: {
|
||||
marginBottom: '1rem',
|
||||
textAlign: 'center',
|
||||
},
|
||||
container: {
|
||||
display: 'flex',
|
||||
},
|
||||
@ -9,7 +25,6 @@ export const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
innerContainer: {
|
||||
width: '60%',
|
||||
minHeight: '100vh',
|
||||
padding: '4rem 3rem',
|
||||
},
|
||||
buttonContainer: {
|
||||
@ -20,14 +35,14 @@ export const useStyles = makeStyles(theme => ({
|
||||
marginRight: '8px',
|
||||
},
|
||||
subtitle: {
|
||||
marginBottom: '0.5rem',
|
||||
fontSize: '1.1rem',
|
||||
margin: '0.5rem 0',
|
||||
},
|
||||
passwordHeader: {
|
||||
marginTop: '2rem',
|
||||
},
|
||||
emailField: {
|
||||
minWidth: '300px',
|
||||
width: '100%',
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
minWidth: '100%',
|
||||
},
|
||||
|
@ -5,13 +5,13 @@ import StandaloneBanner from '../StandaloneBanner/StandaloneBanner';
|
||||
import ResetPasswordDetails from '../common/ResetPasswordDetails/ResetPasswordDetails';
|
||||
|
||||
import { useStyles } from './NewUser.styles';
|
||||
import { useCommonStyles } from '../../../common.styles';
|
||||
import useResetPassword from '../../../hooks/useResetPassword';
|
||||
import StandaloneLayout from '../common/StandaloneLayout/StandaloneLayout';
|
||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||
import InvalidToken from '../common/InvalidToken/InvalidToken';
|
||||
import { IAuthStatus } from '../../../interfaces/user';
|
||||
import AuthOptions from '../common/AuthOptions/AuthOptions';
|
||||
import DividerText from '../../common/DividerText/DividerText';
|
||||
|
||||
interface INewUserProps {
|
||||
user: IAuthStatus;
|
||||
@ -21,26 +21,15 @@ const NewUser = ({ user }: INewUserProps) => {
|
||||
const { token, data, loading, setLoading, invalidToken } =
|
||||
useResetPassword();
|
||||
const ref = useLoading(loading);
|
||||
const commonStyles = useCommonStyles();
|
||||
const styles = useStyles();
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<StandaloneLayout
|
||||
showMenu={false}
|
||||
BannerComponent={
|
||||
<StandaloneBanner showStars title={'Welcome to Unleash'}>
|
||||
<ConditionallyRender
|
||||
condition={data?.createdBy}
|
||||
show={
|
||||
<Typography variant="body1">
|
||||
You have been invited by {data?.createdBy}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</StandaloneBanner>
|
||||
}
|
||||
BannerComponent={<StandaloneBanner title={'Unleash'} />}
|
||||
>
|
||||
<div className={styles.newUser}>
|
||||
<ConditionallyRender
|
||||
condition={invalidToken}
|
||||
show={<InvalidToken />}
|
||||
@ -49,13 +38,33 @@ const NewUser = ({ user }: INewUserProps) => {
|
||||
token={token}
|
||||
setLoading={setLoading}
|
||||
>
|
||||
<h2 className={styles.title}>
|
||||
Enter your personal details and start your
|
||||
journey
|
||||
</h2>
|
||||
<ConditionallyRender
|
||||
condition={data?.createdBy}
|
||||
show={
|
||||
<Typography
|
||||
variant="body1"
|
||||
data-loading
|
||||
className={styles.inviteText}
|
||||
>
|
||||
{data?.createdBy}
|
||||
<br></br> has invited you to join
|
||||
Unleash.
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
|
||||
<Typography
|
||||
data-loading
|
||||
variant="subtitle1"
|
||||
variant="body1"
|
||||
className={styles.subtitle}
|
||||
>
|
||||
Your username is
|
||||
</Typography>
|
||||
|
||||
<TextField
|
||||
data-loading
|
||||
value={data?.email || ''}
|
||||
@ -65,50 +74,28 @@ const NewUser = ({ user }: INewUserProps) => {
|
||||
disabled
|
||||
/>
|
||||
<div className={styles.roleContainer}>
|
||||
<Typography
|
||||
data-loading
|
||||
variant="subtitle1"
|
||||
className={styles.subtitle}
|
||||
>
|
||||
In Unleash your role is:{' '}
|
||||
<i>{data?.role?.name}</i>
|
||||
</Typography>
|
||||
<Typography variant="body1" data-loading>
|
||||
{data?.role?.description}
|
||||
</Typography>
|
||||
<div
|
||||
className={commonStyles.largeDivider}
|
||||
data-loading
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
user?.authDetails?.options?.length > 0
|
||||
user?.authDetails?.options?.length >
|
||||
0
|
||||
}
|
||||
show={
|
||||
<>
|
||||
<Typography data-loading>
|
||||
Login with 3rd party providers
|
||||
</Typography>
|
||||
<DividerText
|
||||
text="sign in with"
|
||||
data-loading
|
||||
/>
|
||||
|
||||
<AuthOptions
|
||||
options={
|
||||
user?.authDetails?.options
|
||||
user?.authDetails
|
||||
?.options
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className={
|
||||
commonStyles.largeDivider
|
||||
}
|
||||
<DividerText
|
||||
text="or set a new password for your account"
|
||||
data-loading
|
||||
/>
|
||||
<Typography
|
||||
className={
|
||||
styles.passwordHeader
|
||||
}
|
||||
data-loading
|
||||
>
|
||||
OR set a new password for your
|
||||
account
|
||||
</Typography>
|
||||
</>
|
||||
}
|
||||
elseShow={
|
||||
@ -124,6 +111,7 @@ const NewUser = ({ user }: INewUserProps) => {
|
||||
</ResetPasswordDetails>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</StandaloneLayout>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,21 +1,19 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, TextField, Typography, IconButton } from '@material-ui/core';
|
||||
import LockRounded from '@material-ui/icons/LockRounded';
|
||||
import { Button, TextField, Typography } from '@material-ui/core';
|
||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||
import { useHistory } from 'react-router';
|
||||
import { useCommonStyles } from '../../../common.styles';
|
||||
import { useStyles } from './PasswordAuth.styles';
|
||||
import { Link } from 'react-router-dom';
|
||||
import useQueryParams from '../../../hooks/useQueryParams';
|
||||
import { GoogleSvg } from '../HostedAuth/Icons';
|
||||
import AuthOptions from '../common/AuthOptions/AuthOptions';
|
||||
import DividerText from '../../common/DividerText/DividerText';
|
||||
|
||||
const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
||||
const commonStyles = useCommonStyles();
|
||||
const styles = useStyles();
|
||||
const history = useHistory();
|
||||
const [showFields, setShowFields] = useState(false);
|
||||
const params = useQueryParams();
|
||||
const [username, setUsername] = useState(params.get('email') || '');
|
||||
const [password, setPassword] = useState('');
|
||||
@ -24,11 +22,6 @@ const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
||||
passwordError: '',
|
||||
});
|
||||
|
||||
const onShowOptions = e => {
|
||||
e.preventDefault();
|
||||
setShowFields(true);
|
||||
};
|
||||
|
||||
const handleSubmit = async evt => {
|
||||
evt.preventDefault();
|
||||
|
||||
@ -110,17 +103,11 @@ const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
||||
autoComplete="true"
|
||||
size="small"
|
||||
/>
|
||||
|
||||
<Link to="/forgotten-password">
|
||||
<Typography variant="body2">
|
||||
Forgot your password?
|
||||
</Typography>
|
||||
</Link>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
style={{ maxWidth: '150px' }}
|
||||
style={{ width: '150px', margin: '1rem auto' }}
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
@ -130,44 +117,23 @@ const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
||||
};
|
||||
|
||||
const renderWithOptions = options => (
|
||||
<div>
|
||||
{options.map(o => (
|
||||
<div
|
||||
key={o.type}
|
||||
className={classnames(
|
||||
styles.contentContainer,
|
||||
commonStyles.contentSpacingY
|
||||
)}
|
||||
>
|
||||
<Button color="primary" variant="outlined" href={o.path} startIcon={o.type === 'google' ? <GoogleSvg /> : <LockRounded />}>
|
||||
{o.message}
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
<ConditionallyRender
|
||||
condition={showFields}
|
||||
show={renderLoginForm()}
|
||||
elseShow={
|
||||
|
||||
<IconButton size="small" onClick={onShowOptions}>
|
||||
Show more options
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<>
|
||||
<AuthOptions options={options} />
|
||||
<DividerText text="Or signin with username" />
|
||||
{renderLoginForm()}
|
||||
</>
|
||||
);
|
||||
|
||||
const { options = [] } = authDetails;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Typography variant="subtitle1">{authDetails.message}</Typography>
|
||||
<>
|
||||
<ConditionallyRender
|
||||
condition={options.length > 0}
|
||||
show={renderWithOptions(options)}
|
||||
elseShow={renderLoginForm()}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,20 @@
|
||||
.container {
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
margin: 0.6rem 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button {
|
||||
min-width: 150px;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,22 @@ import { makeStyles } from '@material-ui/core/styles';
|
||||
export const useStyles = makeStyles(theme => ({
|
||||
title: {
|
||||
color: '#fff',
|
||||
fontSize: '1.2rem',
|
||||
fontWeight: 'bold',
|
||||
marginBottom: '1rem',
|
||||
fontSize: '2rem',
|
||||
marginTop: '5rem',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
textAlign: 'left',
|
||||
fontSize: '1.75rem',
|
||||
marginTop: 0,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
padding: '4rem 2rem',
|
||||
padding: '6rem 4rem',
|
||||
color: '#fff',
|
||||
position: 'relative',
|
||||
borderTopLeftRadius: '3px',
|
||||
borderBottomLeftRadius: '3px',
|
||||
textAlign: 'right',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
padding: '3rem 2rem',
|
||||
},
|
||||
@ -18,9 +26,22 @@ export const useStyles = makeStyles(theme => ({
|
||||
padding: '3rem 1rem',
|
||||
},
|
||||
},
|
||||
bannerSubtitle: {
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
maxWidth: '300px',
|
||||
fontSize: '1.75rem',
|
||||
textAlign: 'left',
|
||||
},
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
display: 'none',
|
||||
},
|
||||
fontSize: '2rem',
|
||||
fontWeight: '300',
|
||||
},
|
||||
switchesContainer: {
|
||||
position: 'absolute',
|
||||
bottom: '40px',
|
||||
bottom: '15px',
|
||||
left: '-50px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
@ -28,46 +49,6 @@ export const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
},
|
||||
switchIcon: {
|
||||
height: '180px',
|
||||
},
|
||||
bottomStar: {
|
||||
position: 'absolute',
|
||||
bottom: '-54px',
|
||||
left: '100px',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
bottomRightStar: {
|
||||
position: 'absolute',
|
||||
bottom: '-100px',
|
||||
left: '200px',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
midRightStar: {
|
||||
position: 'absolute',
|
||||
bottom: '-80px',
|
||||
left: '300px',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
midLeftStar: {
|
||||
position: 'absolute',
|
||||
top: '10px',
|
||||
left: '150px',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
midLeftStarTwo: {
|
||||
position: 'absolute',
|
||||
top: '25px',
|
||||
left: '350px',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display: 'none',
|
||||
},
|
||||
height: '100px',
|
||||
},
|
||||
}));
|
||||
|
@ -2,45 +2,35 @@ import { FC } from 'react';
|
||||
|
||||
import { Typography, useTheme } from '@material-ui/core';
|
||||
import Gradient from '../../common/Gradient/Gradient';
|
||||
import { ReactComponent as StarIcon } from '../../../assets/icons/star.svg';
|
||||
import { ReactComponent as RightToggleIcon } from '../../../assets/icons/toggleRight.svg';
|
||||
import { ReactComponent as LeftToggleIcon } from '../../../assets/icons/toggleLeft.svg';
|
||||
|
||||
import { useStyles } from './StandaloneBanner.styles';
|
||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||
|
||||
interface IStandaloneBannerProps {
|
||||
showStars?: boolean;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const StandaloneBanner: FC<IStandaloneBannerProps> = ({
|
||||
showStars = false,
|
||||
title,
|
||||
children,
|
||||
}) => {
|
||||
const StandaloneBanner: FC<IStandaloneBannerProps> = ({ title, children }) => {
|
||||
const theme = useTheme();
|
||||
const styles = useStyles();
|
||||
return (
|
||||
<Gradient from={theme.palette.primary.main} to={'#173341'}>
|
||||
<Gradient
|
||||
from={theme.palette.primary.main}
|
||||
to={theme.palette.login.gradient.bottom}
|
||||
style={{
|
||||
borderBottomLeftRadius: '3px',
|
||||
borderTopLeftRadius: '3px',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<div className={styles.container}>
|
||||
<Typography variant="h1" className={styles.title}>
|
||||
{title}
|
||||
</Typography>
|
||||
{children}
|
||||
|
||||
<ConditionallyRender
|
||||
condition={showStars}
|
||||
show={
|
||||
<>
|
||||
<StarIcon className={styles.midLeftStarTwo} />
|
||||
<StarIcon className={styles.midLeftStar} />
|
||||
<StarIcon className={styles.midRightStar} />
|
||||
<StarIcon className={styles.bottomRightStar} />
|
||||
<StarIcon className={styles.bottomStar} />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Typography className={styles.bannerSubtitle}>
|
||||
Committed to creating new ways of developing software
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div className={styles.switchesContainer}>
|
||||
|
@ -6,10 +6,13 @@ import PasswordAuth from './PasswordAuth/PasswordAuth';
|
||||
import HostedAuth from './HostedAuth/HostedAuth';
|
||||
import DemoAuth from './DemoAuth';
|
||||
|
||||
const SIMPLE_TYPE = 'unsecure';
|
||||
const DEMO_TYPE = 'demo';
|
||||
const PASSWORD_TYPE = 'password';
|
||||
const HOSTED_TYPE = 'enterprise-hosted';
|
||||
import {
|
||||
SIMPLE_TYPE,
|
||||
DEMO_TYPE,
|
||||
PASSWORD_TYPE,
|
||||
HOSTED_TYPE,
|
||||
} from '../../constants/authTypes';
|
||||
import SecondaryLoginActions from './common/SecondaryLoginActions/SecondaryLoginActions';
|
||||
|
||||
class AuthComponent extends React.Component {
|
||||
static propTypes = {
|
||||
@ -22,16 +25,20 @@ class AuthComponent extends React.Component {
|
||||
|
||||
render() {
|
||||
const authDetails = this.props.user.authDetails;
|
||||
|
||||
if (!authDetails) return null;
|
||||
|
||||
let content;
|
||||
if (authDetails.type === PASSWORD_TYPE) {
|
||||
content = (
|
||||
<>
|
||||
<PasswordAuth
|
||||
passwordLogin={this.props.passwordLogin}
|
||||
authDetails={authDetails}
|
||||
history={this.props.history}
|
||||
/>
|
||||
<SecondaryLoginActions />
|
||||
</>
|
||||
);
|
||||
} else if (authDetails.type === SIMPLE_TYPE) {
|
||||
content = (
|
||||
@ -51,18 +58,21 @@ class AuthComponent extends React.Component {
|
||||
);
|
||||
} else if (authDetails.type === HOSTED_TYPE) {
|
||||
content = (
|
||||
<>
|
||||
<HostedAuth
|
||||
passwordLogin={this.props.passwordLogin}
|
||||
authDetails={authDetails}
|
||||
history={this.props.history}
|
||||
/>
|
||||
<SecondaryLoginActions />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<AuthenticationCustomComponent authDetails={authDetails} />
|
||||
);
|
||||
}
|
||||
return <div>{content}</div>;
|
||||
return <>{content}</>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,14 @@ class AuthenticationCustomComponent extends React.Component {
|
||||
<div>
|
||||
<p>{authDetails.message}</p>
|
||||
<CardActions style={{ textAlign: 'center' }}>
|
||||
<a href={authDetails.path}>
|
||||
<Button>Sign In</Button>
|
||||
<a href={authDetails.path} style={{ width: '100%' }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
style={{ width: '150px', margin: '0 auto' }}
|
||||
>
|
||||
Sign In
|
||||
</Button>
|
||||
</a>
|
||||
</CardActions>
|
||||
</div>
|
||||
|
@ -4,6 +4,7 @@ import { useCommonStyles } from '../../../../common.styles';
|
||||
import { IAuthOptions } from '../../../../interfaces/user';
|
||||
import { ReactComponent as GoogleSvg } from '../../../../assets/icons/google.svg';
|
||||
import LockRounded from '@material-ui/icons/LockRounded';
|
||||
import ConditionallyRender from '../../../common/ConditionallyRender';
|
||||
|
||||
interface IAuthOptionProps {
|
||||
options?: IAuthOptions[];
|
||||
@ -27,13 +28,27 @@ const AuthOptions = ({ options }: IAuthOptionProps) => {
|
||||
variant="outlined"
|
||||
href={o.path}
|
||||
size="small"
|
||||
style={{ maxWidth: '300px' }}
|
||||
style={{ height: '40px', color: '#000' }}
|
||||
startIcon={
|
||||
o.type === 'google' ? (
|
||||
<GoogleSvg />
|
||||
) : (
|
||||
<LockRounded />
|
||||
)
|
||||
<ConditionallyRender
|
||||
condition={o.type === 'google'}
|
||||
show={
|
||||
<GoogleSvg
|
||||
style={{
|
||||
height: '35px',
|
||||
width: '35px',
|
||||
}}
|
||||
/>
|
||||
}
|
||||
elseShow={
|
||||
<LockRounded
|
||||
style={{
|
||||
height: '25px',
|
||||
width: '25px',
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{o.message}
|
||||
|
@ -10,6 +10,8 @@ import { formatApiPath } from '../../../../../utils/format-path';
|
||||
interface IPasswordCheckerProps {
|
||||
password: string;
|
||||
callback: Dispatch<SetStateAction<boolean>>;
|
||||
style?: object;
|
||||
hideOnCompletion?: boolean;
|
||||
}
|
||||
|
||||
interface IErrorResponse {
|
||||
@ -30,7 +32,11 @@ const UPPERCASE_ERROR =
|
||||
const LOWERCASE_ERROR =
|
||||
'The password must contain at least one lowercase letter.';
|
||||
|
||||
const PasswordChecker = ({ password, callback }: IPasswordCheckerProps) => {
|
||||
const PasswordChecker = ({
|
||||
password,
|
||||
callback,
|
||||
style = {},
|
||||
}: IPasswordCheckerProps) => {
|
||||
const styles = useStyles();
|
||||
const [casingError, setCasingError] = useState(true);
|
||||
const [numberError, setNumberError] = useState(true);
|
||||
@ -142,7 +148,12 @@ const PasswordChecker = ({ password, callback }: IPasswordCheckerProps) => {
|
||||
<HelpIcon className={styles.helpIcon} />
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
<div className={styles.container}>
|
||||
<div
|
||||
className={styles.container}
|
||||
style={{
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
<div className={styles.headerContainer}>
|
||||
<div className={styles.checkContainer}>
|
||||
<Typography variant="body2" data-loading>
|
||||
|
@ -4,9 +4,11 @@ export const useStyles = makeStyles(theme => ({
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
maxWidth: '300px',
|
||||
position: 'relative',
|
||||
},
|
||||
button: {
|
||||
width: '150px',
|
||||
margin: '1rem auto',
|
||||
display: 'block',
|
||||
},
|
||||
}));
|
||||
|
@ -28,6 +28,7 @@ const ResetPasswordForm = ({ token, setLoading }: IResetPasswordProps) => {
|
||||
const commonStyles = useCommonStyles();
|
||||
const [apiError, setApiError] = useState(false);
|
||||
const [password, setPassword] = useState('');
|
||||
const [showPasswordChecker, setShowPasswordChecker] = useState(false);
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
const [matchingPasswords, setMatchingPasswords] = useState(false);
|
||||
const [validOwaspPassword, setValidOwaspPassword] = useState(false);
|
||||
@ -102,10 +103,6 @@ const ResetPasswordForm = ({ token, setLoading }: IResetPasswordProps) => {
|
||||
styles.container
|
||||
)}
|
||||
>
|
||||
<PasswordChecker
|
||||
password={password}
|
||||
callback={setValidOwaspPasswordMemo}
|
||||
/>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
size="small"
|
||||
@ -113,6 +110,7 @@ const ResetPasswordForm = ({ token, setLoading }: IResetPasswordProps) => {
|
||||
placeholder="Password"
|
||||
value={password || ''}
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
onFocus={() => setShowPasswordChecker(true)}
|
||||
autoComplete="password"
|
||||
data-loading
|
||||
/>
|
||||
@ -126,6 +124,17 @@ const ResetPasswordForm = ({ token, setLoading }: IResetPasswordProps) => {
|
||||
autoComplete="confirm-password"
|
||||
data-loading
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={showPasswordChecker}
|
||||
show={
|
||||
<PasswordChecker
|
||||
password={password}
|
||||
callback={setValidOwaspPasswordMemo}
|
||||
style={{ marginBottom: '1rem' }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PasswordMatcher
|
||||
started={started}
|
||||
matchingPasswords={matchingPasswords}
|
||||
|
@ -0,0 +1,18 @@
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
export const useStyles = makeStyles(theme => ({
|
||||
container: {
|
||||
margin: 'auto auto 0 auto',
|
||||
width: '200px',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
marginTop: '1rem',
|
||||
},
|
||||
},
|
||||
link: {
|
||||
textDecoration: 'none',
|
||||
fontWeight: 'bold',
|
||||
color: theme.palette.primary.main,
|
||||
textAlign: 'center',
|
||||
},
|
||||
text: { fontWeight: 'bold', marginBottom: '0.5rem' },
|
||||
}));
|
@ -0,0 +1,29 @@
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useStyles } from './SecondaryLoginActions.styles';
|
||||
|
||||
const SecondaryLoginActions = () => {
|
||||
const styles = useStyles();
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Link to="/forgotten-password" className={styles.link}>
|
||||
<Typography variant="body2" className={styles.text}>
|
||||
Forgot password?
|
||||
</Typography>
|
||||
</Link>
|
||||
<Typography variant="body2">
|
||||
Don't have an account?{' '}
|
||||
<a
|
||||
href="https://www.getunleash.io/plans"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={styles.link}
|
||||
>
|
||||
Sign up
|
||||
</a>
|
||||
</Typography>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SecondaryLoginActions;
|
@ -2,28 +2,31 @@ import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
export const useStyles = makeStyles(theme => ({
|
||||
container: {
|
||||
padding: '4rem',
|
||||
background: '#3a5663',
|
||||
display: 'flex',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
flexDirection: 'column',
|
||||
},
|
||||
overflow: 'hidden',
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
padding: '0',
|
||||
},
|
||||
minHeight: '100vh',
|
||||
},
|
||||
leftContainer: {
|
||||
width: '40%',
|
||||
minHeight: '100vh',
|
||||
borderRadius: '3px',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
width: '100%',
|
||||
minHeight: 'auto',
|
||||
},
|
||||
},
|
||||
bannerSubtitle: {
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
maxWidth: '300px',
|
||||
},
|
||||
},
|
||||
rightContainer: {
|
||||
width: '60%',
|
||||
minHeight: '100vh',
|
||||
flex: '1',
|
||||
borderTopRightRadius: '3px',
|
||||
borderBottomRightRadius: '3px',
|
||||
backgroundColor: '#fff',
|
||||
position: 'relative',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
width: '100%',
|
||||
@ -31,27 +34,16 @@ export const useStyles = makeStyles(theme => ({
|
||||
minHeight: 'auto',
|
||||
},
|
||||
},
|
||||
menu: {
|
||||
position: 'absolute',
|
||||
right: '20px',
|
||||
top: '20px',
|
||||
'& a': {
|
||||
textDecoration: 'none',
|
||||
color: '#000',
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
'& a': {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
},
|
||||
title: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.2rem',
|
||||
marginBottom: '1rem',
|
||||
},
|
||||
innerRightContainer: {
|
||||
padding: '4rem 3rem',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
padding: '6rem 3rem',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
padding: '2rem 2rem',
|
||||
},
|
||||
|
@ -1,11 +1,7 @@
|
||||
import { FC } from 'react';
|
||||
import StandaloneBanner from '../../StandaloneBanner/StandaloneBanner';
|
||||
|
||||
import { Typography } from '@material-ui/core';
|
||||
|
||||
import { useStyles } from './StandaloneLayout.styles';
|
||||
import ConditionallyRender from '../../../common/ConditionallyRender';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
interface IStandaloneLayout {
|
||||
BannerComponent?: JSX.Element;
|
||||
@ -14,39 +10,20 @@ interface IStandaloneLayout {
|
||||
|
||||
const StandaloneLayout: FC<IStandaloneLayout> = ({
|
||||
children,
|
||||
showMenu = true,
|
||||
BannerComponent,
|
||||
}) => {
|
||||
const styles = useStyles();
|
||||
const location = useLocation();
|
||||
|
||||
let banner = (
|
||||
<StandaloneBanner title="Unleash">
|
||||
<Typography variant="subtitle1" className={styles.bannerSubtitle}>
|
||||
Committed to creating new ways of developing software.
|
||||
</Typography>
|
||||
</StandaloneBanner>
|
||||
);
|
||||
let banner = <StandaloneBanner title="Unleash" />;
|
||||
|
||||
if (BannerComponent) {
|
||||
banner = BannerComponent;
|
||||
}
|
||||
|
||||
const isLoginpage = location.pathname.includes('login');
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.leftContainer}>{banner}</div>
|
||||
<div className={styles.rightContainer}>
|
||||
<ConditionallyRender
|
||||
condition={showMenu && !isLoginpage}
|
||||
show={
|
||||
<div className={styles.menu}>
|
||||
<Link to="/login">Login</Link>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className={styles.innerRightContainer}>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
5
frontend/src/constants/authTypes.ts
Normal file
5
frontend/src/constants/authTypes.ts
Normal file
@ -0,0 +1,5 @@
|
||||
/* AUTH TYPES */
|
||||
export const SIMPLE_TYPE = 'unsecure';
|
||||
export const DEMO_TYPE = 'demo';
|
||||
export const PASSWORD_TYPE = 'password';
|
||||
export const HOSTED_TYPE = 'enterprise-hosted';
|
13
frontend/src/interfaces/palette.d.ts
vendored
13
frontend/src/interfaces/palette.d.ts
vendored
@ -1,10 +1,19 @@
|
||||
import * as createPalette from '@material-ui/core/styles/createPalette';
|
||||
|
||||
declare module '@material-ui/core/styles/createPalette' {
|
||||
interface PaletteOptions {
|
||||
borders?: PaletteColorOptions;
|
||||
login?: ILoginPaletteOptions;
|
||||
}
|
||||
interface Palette {
|
||||
borders?: PaletteColor;
|
||||
}
|
||||
}
|
||||
|
||||
interface ILoginPaletteOptions {
|
||||
gradient?: IGradientPaletteOptions;
|
||||
main?: string;
|
||||
}
|
||||
|
||||
interface IGradientPaletteOptions {
|
||||
top: string;
|
||||
bottom: string;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user