update: seperate routes for login and signup added
This commit is contained in:
parent
2c4bc9adb6
commit
a638f02014
46
app/package-lock.json
generated
46
app/package-lock.json
generated
|
@ -17,10 +17,12 @@
|
|||
"react-dom": "^17.0.2",
|
||||
"react-is": "^17.0.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"styled-components": "^5.3.0",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-router-dom": "^5.1.8"
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"@types/styled-components": "^5.1.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@authorizerdev/authorizer-js": {
|
||||
|
@ -271,6 +273,16 @@
|
|||
"integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/hoist-non-react-statics": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
|
||||
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
|
||||
|
@ -320,6 +332,17 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
|
||||
},
|
||||
"node_modules/@types/styled-components": {
|
||||
"version": "5.1.25",
|
||||
"resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.25.tgz",
|
||||
"integrity": "sha512-fgwl+0Pa8pdkwXRoVPP9JbqF0Ivo9llnmsm+7TCI330kbPIFd9qv1Lrhr37shf4tnxCOSu+/IgqM7uJXLWZZNQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/hoist-non-react-statics": "*",
|
||||
"@types/react": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
|
@ -1016,6 +1039,16 @@
|
|||
"integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/hoist-non-react-statics": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
|
||||
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
|
||||
|
@ -1065,6 +1098,17 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
|
||||
},
|
||||
"@types/styled-components": {
|
||||
"version": "5.1.25",
|
||||
"resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.25.tgz",
|
||||
"integrity": "sha512-fgwl+0Pa8pdkwXRoVPP9JbqF0Ivo9llnmsm+7TCI330kbPIFd9qv1Lrhr37shf4tnxCOSu+/IgqM7uJXLWZZNQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/hoist-non-react-statics": "*",
|
||||
"@types/react": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
"react-dom": "^17.0.2",
|
||||
"react-is": "^17.0.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"typescript": "^4.3.5"
|
||||
"typescript": "^4.3.5",
|
||||
"styled-components": "^5.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-router-dom": "^5.1.8"
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"@types/styled-components": "^5.1.11"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,28 @@
|
|||
import React, { useEffect, lazy, Suspense } from 'react';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
import { useAuthorizer } from '@authorizerdev/authorizer-react';
|
||||
import styled, { ThemeProvider } from 'styled-components';
|
||||
import SetupPassword from './pages/setup-password';
|
||||
import { hasWindow, createRandomString } from './utils/common';
|
||||
import { theme } from './theme';
|
||||
|
||||
const ResetPassword = lazy(() => import('./pages/rest-password'));
|
||||
const Login = lazy(() => import('./pages/login'));
|
||||
const Dashboard = lazy(() => import('./pages/dashboard'));
|
||||
const SignUp = lazy(() => import('./pages/signup'));
|
||||
|
||||
const Wrapper = styled.div`
|
||||
font-family: ${(props) => props.theme.fonts.fontStack};
|
||||
color: ${(props) => props.theme.colors.textColor};
|
||||
font-size: ${(props) => props.theme.fonts.mediumText};
|
||||
box-sizing: border-box;
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function Root({
|
||||
globalState,
|
||||
|
@ -14,6 +31,29 @@ export default function Root({
|
|||
}) {
|
||||
const { token, loading, config } = useAuthorizer();
|
||||
|
||||
const searchParams = new URLSearchParams(
|
||||
hasWindow() ? window.location.search : ``
|
||||
);
|
||||
const state = searchParams.get('state') || createRandomString();
|
||||
const scope = searchParams.get('scope')
|
||||
? searchParams.get('scope')?.toString().split(' ')
|
||||
: ['openid', 'profile', 'email'];
|
||||
|
||||
const urlProps: Record<string, any> = {
|
||||
state,
|
||||
scope,
|
||||
};
|
||||
|
||||
const redirectURL =
|
||||
searchParams.get('redirect_uri') || searchParams.get('redirectURL');
|
||||
if (redirectURL) {
|
||||
urlProps.redirectURL = redirectURL;
|
||||
} else {
|
||||
urlProps.redirectURL = hasWindow() ? window.location.origin : redirectURL;
|
||||
}
|
||||
|
||||
urlProps.redirect_uri = urlProps.redirectURL;
|
||||
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
let redirectURL = config.redirectURL || '/app';
|
||||
|
@ -54,17 +94,24 @@ export default function Root({
|
|||
|
||||
return (
|
||||
<Suspense fallback={<></>}>
|
||||
<Switch>
|
||||
<Route path="/app" exact>
|
||||
<Login />
|
||||
</Route>
|
||||
<Route path="/app/reset-password">
|
||||
<ResetPassword />
|
||||
</Route>
|
||||
<Route path="/app/setup-password">
|
||||
<SetupPassword />
|
||||
</Route>
|
||||
</Switch>
|
||||
<ThemeProvider theme={theme}>
|
||||
<Wrapper>
|
||||
<Switch>
|
||||
<Route path="/app" exact>
|
||||
<Login urlProps={urlProps} />
|
||||
</Route>
|
||||
<Route path="/app/signup" exact>
|
||||
<SignUp urlProps={urlProps} />
|
||||
</Route>
|
||||
<Route path="/app/reset-password">
|
||||
<ResetPassword />
|
||||
</Route>
|
||||
<Route path="/app/setup-password">
|
||||
<SetupPassword />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Wrapper>
|
||||
</ThemeProvider>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,82 @@
|
|||
import React, { Fragment } from 'react';
|
||||
import { Authorizer } from '@authorizerdev/authorizer-react';
|
||||
import React, { Fragment, useState } from 'react';
|
||||
import {
|
||||
AuthorizerBasicAuthLogin,
|
||||
AuthorizerForgotPassword,
|
||||
AuthorizerMagicLinkLogin,
|
||||
AuthorizerSocialLogin,
|
||||
useAuthorizer,
|
||||
} from '@authorizerdev/authorizer-react';
|
||||
import styled from 'styled-components';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export default function Login() {
|
||||
const enum VIEW_TYPES {
|
||||
LOGIN = 'login',
|
||||
FORGOT_PASSWORD = 'forgot-password',
|
||||
}
|
||||
|
||||
const Footer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 15px;
|
||||
`;
|
||||
|
||||
const FooterContent = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
`;
|
||||
|
||||
export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||
const { config } = useAuthorizer();
|
||||
const [view, setView] = useState<VIEW_TYPES>(VIEW_TYPES.LOGIN);
|
||||
return (
|
||||
<Fragment>
|
||||
<Authorizer />
|
||||
{view === VIEW_TYPES.LOGIN && (
|
||||
<Fragment>
|
||||
<h1 style={{ textAlign: 'center' }}>Login</h1>
|
||||
<br />
|
||||
<AuthorizerSocialLogin urlProps={urlProps} />
|
||||
{config.is_basic_authentication_enabled &&
|
||||
!config.is_magic_link_login_enabled && (
|
||||
<AuthorizerBasicAuthLogin urlProps={urlProps} />
|
||||
)}
|
||||
{config.is_magic_link_login_enabled && (
|
||||
<AuthorizerMagicLinkLogin urlProps={urlProps} />
|
||||
)}
|
||||
<Footer>
|
||||
<Link
|
||||
to="#"
|
||||
onClick={() => setView(VIEW_TYPES.FORGOT_PASSWORD)}
|
||||
style={{ marginBottom: 10 }}
|
||||
>
|
||||
Forgot Password?
|
||||
</Link>
|
||||
</Footer>
|
||||
</Fragment>
|
||||
)}
|
||||
{view === VIEW_TYPES.FORGOT_PASSWORD && (
|
||||
<Fragment>
|
||||
<h1 style={{ textAlign: 'center' }}>Forgot Password</h1>
|
||||
<AuthorizerForgotPassword urlProps={urlProps} />
|
||||
<Footer>
|
||||
<Link
|
||||
to="#"
|
||||
onClick={() => setView(VIEW_TYPES.LOGIN)}
|
||||
style={{ marginBottom: 10 }}
|
||||
>
|
||||
Back
|
||||
</Link>
|
||||
</Footer>
|
||||
</Fragment>
|
||||
)}
|
||||
{config.is_sign_up_enabled && (
|
||||
<FooterContent>
|
||||
Don't have an account? <Link to="/app/signup"> Sign Up</Link>
|
||||
</FooterContent>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
|
28
app/src/pages/signup.tsx
Normal file
28
app/src/pages/signup.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import React, { Fragment } from 'react';
|
||||
import { AuthorizerSignup } from '@authorizerdev/authorizer-react';
|
||||
import styled from 'styled-components';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const FooterContent = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
`;
|
||||
|
||||
export default function SignUp({
|
||||
urlProps,
|
||||
}: {
|
||||
urlProps: Record<string, any>;
|
||||
}) {
|
||||
return (
|
||||
<Fragment>
|
||||
<h1 style={{ textAlign: 'center' }}>Sign Up</h1>
|
||||
<br />
|
||||
<AuthorizerSignup urlProps={urlProps} />
|
||||
<FooterContent>
|
||||
Already have an account? <Link to="/app"> Login</Link>
|
||||
</FooterContent>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
28
app/src/theme.ts
Normal file
28
app/src/theme.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
// colors: https://tailwindcss.com/docs/customizing-colors
|
||||
|
||||
export const theme = {
|
||||
colors: {
|
||||
primary: '#3B82F6',
|
||||
primaryDisabled: '#60A5FA',
|
||||
gray: '#D1D5DB',
|
||||
danger: '#DC2626',
|
||||
success: '#10B981',
|
||||
textColor: '#374151',
|
||||
},
|
||||
fonts: {
|
||||
// typography
|
||||
fontStack: '-apple-system, system-ui, sans-serif',
|
||||
|
||||
// font sizes
|
||||
largeText: '18px',
|
||||
mediumText: '14px',
|
||||
smallText: '12px',
|
||||
tinyText: '10px',
|
||||
},
|
||||
|
||||
radius: {
|
||||
card: '5px',
|
||||
button: '5px',
|
||||
input: '5px',
|
||||
},
|
||||
};
|
|
@ -20,3 +20,5 @@ export const createQueryParams = (params: any) => {
|
|||
.map((k) => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
|
||||
.join('&');
|
||||
};
|
||||
|
||||
export const hasWindow = (): boolean => typeof window !== 'undefined';
|
||||
|
|
Loading…
Reference in New Issue
Block a user