Compare commits

...

4 Commits

Author SHA1 Message Date
Lakhan Samani
7b13034081 fix: dashboard 2022-05-25 16:34:54 +05:30
Lakhan Samani
7c16900618 Merge pull request #168 from anik-ghosh-au7/fix/app-routes
update: separate routes for login and signup added
2022-05-25 16:07:15 +05:30
Lakhan Samani
d722fe258d Merge pull request #173 from authorizerdev/feat/logging
feat: add logging system
2022-05-25 15:07:28 +05:30
anik-ghosh-au7
a638f02014 update: seperate routes for login and signup added 2022-05-18 20:04:29 +05:30
14 changed files with 264 additions and 36 deletions

46
app/package-lock.json generated
View File

@@ -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",

View File

@@ -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"
}
}

View File

@@ -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>
);
}

View File

@@ -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
View 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
View 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',
},
};

View File

@@ -20,3 +20,5 @@ export const createQueryParams = (params: any) => {
.map((k) => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
.join('&');
};
export const hasWindow = (): boolean => typeof window !== 'undefined';

View File

@@ -23,7 +23,6 @@ const theme = extendTheme({
styles: {
global: {
'html, body, #root': {
fontFamily: 'Avenir, Helvetica, Arial, sans-serif',
height: '100%',
outline: 'none',
},

View File

@@ -23,7 +23,7 @@ const OAuthConfig = ({
<div>
<Box>
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={6}>
Your instance information
Authorizer Config
</Text>
<Stack spacing={6} padding="2% 0%">
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>

View File

@@ -13,6 +13,7 @@ import {
Textarea,
Switch,
Code,
Text,
} from '@chakra-ui/react';
import {
FaRegClone,
@@ -179,14 +180,14 @@ const InputField = ({
if (Object.values(ArrayInputType).includes(inputType)) {
return (
<Flex
border="1px solid #e2e8f0"
w="100%"
borderRadius={5}
paddingTop="0.5%"
overflowX={variables[inputType].length > 3 ? "scroll" : "hidden"}
overflowY="hidden"
justifyContent="start"
alignItems="center"
border="1px solid #e2e8f0"
w="100%"
borderRadius={5}
paddingTop="0.5%"
overflowX={variables[inputType].length > 3 ? 'scroll' : 'hidden'}
overflowY="hidden"
justifyContent="start"
alignItems="center"
>
{variables[inputType].map((role: string, index: number) => (
<Box key={index} margin="0.5%" role="group">
@@ -301,7 +302,9 @@ const InputField = ({
if (Object.values(SwitchInputType).includes(inputType)) {
return (
<Flex w="25%" justifyContent="space-between">
<Code h="75%">Off</Code>
<Text h="75%" fontWeight="bold" marginRight="2">
Off
</Text>
<Switch
size="md"
isChecked={variables[inputType]}
@@ -312,7 +315,9 @@ const InputField = ({
});
}}
/>
<Code h="75%">On</Code>
<Text h="75%" fontWeight="bold" marginLeft="2">
On
</Text>
</Flex>
);
}

View File

@@ -119,7 +119,7 @@ interface SidebarProps extends BoxProps {
export const Sidebar = ({ onClose, ...rest }: SidebarProps) => {
const { pathname } = useLocation();
const [{ fetching, data }] = useQuery({ query: MetaQuery });
const [{ data }] = useQuery({ query: MetaQuery });
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
return (
<Box
@@ -127,7 +127,7 @@ export const Sidebar = ({ onClose, ...rest }: SidebarProps) => {
bg={useColorModeValue('white', 'gray.900')}
borderRight="1px"
borderRightColor={useColorModeValue('gray.200', 'gray.700')}
w={{ base: 'full', md: 60 }}
w={{ base: 'full', md: '64' }}
pos="fixed"
h="full"
{...rest}
@@ -137,7 +137,7 @@ export const Sidebar = ({ onClose, ...rest }: SidebarProps) => {
alignItems="center"
mx="18"
justifyContent="space-between"
flexDirection="column"
flexDirection="row"
>
<NavLink to="/">
<Flex alignItems="center" mt="6">
@@ -298,7 +298,7 @@ export const MobileNav = ({ onOpen, ...rest }: MobileProps) => {
return (
<Flex
ml={{ base: 0, md: 60 }}
ml={{ base: 0, md: 64 }}
px={{ base: 4, md: 4 }}
height="20"
position="fixed"

View File

@@ -20,6 +20,7 @@ export function AuthLayout({ children }: { children: React.ReactNode }) {
alignItems="center"
justifyContent="center"
direction={['column', 'column']}
padding={['2%', '2%', '2%', '2%']}
>
<Flex alignItems="center" maxW="100%">
<Image

View File

@@ -31,7 +31,7 @@ export function DashboardLayout({ children }: { children: ReactNode }) {
</Drawer>
{/* mobilenav */}
<MobileNav onOpen={onOpen} />
<Box ml={{ base: 0, md: 60 }} p="4" pt="24">
<Box ml={{ base: 0, md: '64' }} p="4" pt="24">
{children}
</Box>
</Box>

View File

@@ -101,10 +101,10 @@ export default function Auth() {
</FormControl>
<Button
isLoading={signUpResult.fetching || loginResult.fetching}
loadingText="Submitting"
colorScheme="blue"
size="lg"
w="100%"
d="block"
type="submit"
>
{isLogin ? 'Login' : 'Sign up'}