From a638f020145bb4b0e0891abdc93557ed9856a92b Mon Sep 17 00:00:00 2001 From: anik-ghosh-au7 Date: Wed, 18 May 2022 20:04:29 +0530 Subject: [PATCH] update: seperate routes for login and signup added --- app/package-lock.json | 46 ++++++++++++++++++++++- app/package.json | 6 ++- app/src/Root.tsx | 69 ++++++++++++++++++++++++++++------ app/src/pages/login.tsx | 80 ++++++++++++++++++++++++++++++++++++++-- app/src/pages/signup.tsx | 28 ++++++++++++++ app/src/theme.ts | 28 ++++++++++++++ app/src/utils/common.ts | 2 + 7 files changed, 241 insertions(+), 18 deletions(-) create mode 100644 app/src/pages/signup.tsx create mode 100644 app/src/theme.ts diff --git a/app/package-lock.json b/app/package-lock.json index 7097dcb..79b6010 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -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", diff --git a/app/package.json b/app/package.json index 8a3b954..aed0f07 100644 --- a/app/package.json +++ b/app/package.json @@ -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" } } diff --git a/app/src/Root.tsx b/app/src/Root.tsx index 8707a2b..fbd6bb0 100644 --- a/app/src/Root.tsx +++ b/app/src/Root.tsx @@ -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 = { + 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 ( }> - - - - - - - - - - - + + + + + + + + + + + + + + + + + + ); } diff --git a/app/src/pages/login.tsx b/app/src/pages/login.tsx index 2322e80..b67f9fc 100644 --- a/app/src/pages/login.tsx +++ b/app/src/pages/login.tsx @@ -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 }) { + const { config } = useAuthorizer(); + const [view, setView] = useState(VIEW_TYPES.LOGIN); return ( - + {view === VIEW_TYPES.LOGIN && ( + +

Login

+
+ + {config.is_basic_authentication_enabled && + !config.is_magic_link_login_enabled && ( + + )} + {config.is_magic_link_login_enabled && ( + + )} +
+ setView(VIEW_TYPES.FORGOT_PASSWORD)} + style={{ marginBottom: 10 }} + > + Forgot Password? + +
+
+ )} + {view === VIEW_TYPES.FORGOT_PASSWORD && ( + +

Forgot Password

+ +
+ setView(VIEW_TYPES.LOGIN)} + style={{ marginBottom: 10 }} + > + Back + +
+
+ )} + {config.is_sign_up_enabled && ( + + Don't have an account? Sign Up + + )}
); } diff --git a/app/src/pages/signup.tsx b/app/src/pages/signup.tsx new file mode 100644 index 0000000..57fd76c --- /dev/null +++ b/app/src/pages/signup.tsx @@ -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; +}) { + return ( + +

Sign Up

+
+ + + Already have an account? Login + +
+ ); +} diff --git a/app/src/theme.ts b/app/src/theme.ts new file mode 100644 index 0000000..50163e5 --- /dev/null +++ b/app/src/theme.ts @@ -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', + }, +}; diff --git a/app/src/utils/common.ts b/app/src/utils/common.ts index 278e4dd..04a3d42 100644 --- a/app/src/utils/common.ts +++ b/app/src/utils/common.ts @@ -20,3 +20,5 @@ export const createQueryParams = (params: any) => { .map((k) => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) .join('&'); }; + +export const hasWindow = (): boolean => typeof window !== 'undefined';