Browse Source

added user creation

feature/qrscanner
Nareshkumar Rao 3 years ago
parent
commit
2349e24726
  1. 1
      .prettierrc.json
  2. 3
      package.json
  3. 14
      src/App.js
  4. 6
      src/app/store.js
  5. 8
      src/features/auth/authSlice.js
  6. 129
      src/screens/CreateScreen.js
  7. 54
      src/screens/HomeScreen.js
  8. 98
      src/screens/LoginScreen.js
  9. 5
      yarn.lock

1
.prettierrc.json

@ -0,0 +1 @@
{}

3
package.json

@ -42,5 +42,8 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
},
"devDependencies": {
"prettier": "2.3.2"
} }
} }

14
src/App.js

@ -1,12 +1,9 @@
import {
ChakraProvider,
theme
} from '@chakra-ui/react';
import { ChakraProvider, theme } from '@chakra-ui/react';
import { React } from 'react'; import { React } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom'; import { Redirect, Route, Switch } from 'react-router-dom';
import Home from './screens/HomeScreen'
import Login from './screens/LoginScreen'
import Home from './screens/HomeScreen';
import Login from './screens/LoginScreen';
import Create from './screens/CreateScreen';
function App() { function App() {
return ( return (
@ -18,7 +15,8 @@ function App() {
<Route path="/login"> <Route path="/login">
<Login /> <Login />
</Route> </Route>
<Route path="/validate">
<Route path="/create">
<Create />
</Route> </Route>
<Route path="/"> <Route path="/">
<Redirect to="/home" /> <Redirect to="/home" />

6
src/app/store.js

@ -1,8 +1,8 @@
import { configureStore } from "@reduxjs/toolkit";
import authSlice from "../features/auth/authSlice";
import { configureStore } from '@reduxjs/toolkit';
import authSlice from '../features/auth/authSlice';
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
auth: authSlice, auth: authSlice,
}, },
})
});

8
src/features/auth/authSlice.js

@ -1,8 +1,8 @@
import { createSlice } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
const initialState = { const initialState = {
isAuthenticated: Cookies.get("authorized"),
isAuthenticated: Cookies.get('authorized'),
}; };
export const authSlice = createSlice({ export const authSlice = createSlice({
@ -12,12 +12,12 @@ export const authSlice = createSlice({
authLogin: (state, action) => { authLogin: (state, action) => {
state.isAuthenticated = true; state.isAuthenticated = true;
}, },
authLogout: (state) => {
authLogout: state => {
state.isAuthenticated = false; state.isAuthenticated = false;
}, },
}, },
}); });
export const {authLogin, authLogout} = authSlice.actions;
export const { authLogin, authLogout } = authSlice.actions;
export default authSlice.reducer; export default authSlice.reducer;

129
src/screens/CreateScreen.js

@ -0,0 +1,129 @@
import { FormControl, Box, Flex, Image, FormLabel, Input, Select, Heading, Button, useToast } from '@chakra-ui/react';
import axios from 'axios';
import { useState } from 'react';
import { useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { authLogin } from '../features/auth/authSlice';
function OrgSelect(props) {
const orgs = ["MISI: Solidariti", "UNDI18"];
const orgOptions = orgs.map((name) => {
return (
<option value={name}>{name}</option>
)
});
return (
<Select placeholder={props.placeholder} onChange={props.onChange}>
{orgOptions}
</Select>
);
}
function Create() {
const dispatch = useDispatch();
const toast = useToast();
const history = useHistory();
const [name, setName] = useState(null);
const [email, setEmail] = useState(null);
const [phoneNumber, setPhoneNumber] = useState(null);
const [org, setOrg] = useState(null);
const [password, setPassword] = useState(null);
const handleSubmit = (e) => {
e.preventDefault();
if (!name | !email | !phoneNumber | !org | !password) {
toast({
title: 'Problem!',
description: 'Please fill in all the fields',
status: 'error',
duration: 2000,
isClosable: true,
});
return;
}
axios
.post(
`${process.env.REACT_APP_API_URL}/create`,
{
name: name,
email: email,
org: org,
phoneNumber: org,
password: password,
},
{
withCredentials: true,
}
)
.then(response => {
if (response.data.success) {
dispatch(authLogin());
history.push('/home');
} else {
toast({
title: 'An error occurred',
description: response.data.message,
status: 'error',
duration: 5000,
isClosable: true,
});
}
})
.catch(e=>{
if(e.response.status === 401){
toast({
title: 'Verification Error',
description: "You couldn't be verified. Please try scanning the verification QR Code again.",
status: 'error',
duration: 9000,
isClosable: true,
});
}
});
}
return (
<Flex
height="100vh"
background="teal.100"
alignItems="center"
justifyContent="center"
>
<Flex direction="column" background="white" p={12} rounded={6}>
<Heading mb={6}>
Create Account
</Heading>
<form onSubmit={handleSubmit}>
<FormControl mb={6}>
<FormLabel>Name:</FormLabel>
<Input onChange={e => setName(e.target.value)} />
</FormControl>
<FormControl mb={6}>
<FormLabel >Email:</FormLabel>
<Input type="email" onChange={e => setEmail(e.target.value)} />
</FormControl>
<FormControl mb={6}>
<FormLabel>Phone Number:</FormLabel>
<Input onChange={e => setPhoneNumber(e.target.value)} />
</FormControl>
<FormControl mb={6}>
<FormLabel>Organization:</FormLabel>
<OrgSelect placeholder="Select Organization" onChange={e => setOrg(e.target.value)} />
</FormControl>
<FormControl mb={6}>
<FormLabel>Password:</FormLabel>
<Input type="password" onChange={e => setPassword(e.target.value)} />
</FormControl>
<Button type="submit">Create!</Button>
</form>
</Flex>
</Flex>
)
}
export default Create;

54
src/screens/HomeScreen.js

@ -1,54 +1,52 @@
import {
Box, Flex, Image
} from '@chakra-ui/react';
import { Box, Flex, Image } from '@chakra-ui/react';
import axios from 'axios'; import axios from 'axios';
import { React, useState } from 'react'; import { React, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Redirect } from 'react-router-dom'; import { Redirect } from 'react-router-dom';
import { authLogout } from '../features/auth/authSlice'; import { authLogout } from '../features/auth/authSlice';
function QRCode(){
function QRCode() {
const [url, setURL] = useState(null); const [url, setURL] = useState(null);
const dispatch = useDispatch(); const dispatch = useDispatch();
if(!url){
axios.get(`${process.env.REACT_APP_API_URL}/code`,{withCredentials:true})
.then(response =>{
if(!response.data.error){
if (!url) {
axios
.get(`${process.env.REACT_APP_API_URL}/code`, { withCredentials: true })
.then(response => {
if (!response.data.error) {
setURL(response.data.data); setURL(response.data.data);
} }
}) })
.catch((err)=>{
if(err.response.status === 401){
.catch(err => {
if (err.response.status === 401) {
dispatch(authLogout()); dispatch(authLogout());
} }
}); });
} }
if(url){
return (
<Image src={url} />
)
}else{
return (
<Box />
)
}
if (url) {
return <Image src={url} />;
} else {
return <Box />;
} }
}
function Home() {
const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
if (!isAuthenticated) return <Redirect to="/login" />
function Home() {
const isAuthenticated = useSelector(state => state.auth.isAuthenticated);
if (!isAuthenticated) return <Redirect to="/login" />;
return ( return (
<Flex height="100vh" background="teal.100" alignItems="center" justifyContent="center">
<Flex
height="100vh"
background="teal.100"
alignItems="center"
justifyContent="center"
>
<Flex direction="column" background="white" p={12} rounded={6}> <Flex direction="column" background="white" p={12} rounded={6}>
<QRCode/>
<QRCode />
</Flex> </Flex>
</Flex> </Flex>
); );
}
}
export default Home;
export default Home;

98
src/screens/LoginScreen.js

@ -1,11 +1,17 @@
import { import {
Button, Divider, Flex, FormControl,
FormLabel, Heading, Input, useToast
Button,
Divider,
Flex,
FormControl,
FormLabel,
Heading,
Input,
useToast,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import axios from 'axios'; import axios from 'axios';
import { React, useState } from 'react'; import { React, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { Redirect, useHistory } from 'react-router-dom';
import { authLogin } from '../features/auth/authSlice'; import { authLogin } from '../features/auth/authSlice';
function Login() { function Login() {
@ -15,46 +21,51 @@ function Login() {
const history = useHistory(); const history = useHistory();
const dispatch = useDispatch(); const dispatch = useDispatch();
const handleSubmit = (e) => {
const isAuthenticated = useSelector(state => state.auth.isAuthenticated);
if (isAuthenticated) return <Redirect to="/home" />;
if(!email | !password){
const handleSubmit = e => {
if (!email | !password) {
toast({ toast({
title: "Invalid Login",
description: "Please fill in email and password",
status: "error",
title: 'Invalid Login',
description: 'Please fill in email and password',
status: 'error',
duration: 9000, duration: 9000,
isClosable: true, isClosable: true,
}); });
return; return;
} }
axios.post(`${process.env.REACT_APP_API_URL}/login`,{
axios
.post(
`${process.env.REACT_APP_API_URL}/login`,
{
email: email, email: email,
password: password, password: password,
}, },
{ {
withCredentials: true, withCredentials: true,
})
.then(response =>{
if(response.data.authorized){
}
)
.then(response => {
if (response.data.authorized) {
dispatch(authLogin()); dispatch(authLogin());
history.push("/home");
}else{
history.push('/home');
} else {
toast({ toast({
title: "An error occurred",
title: 'An error occurred',
description: response.data.message, description: response.data.message,
status: "error",
status: 'error',
duration: 9000, duration: 9000,
isClosable: true, isClosable: true,
}); });
} }
}) })
.catch((err)=>{
.catch(err => {
toast({ toast({
title: "An error occurred",
description: "Sorry, an error occurred on our side.",
status: "error",
title: 'An error occurred',
description: 'Sorry, an error occurred on our side.',
status: 'error',
duration: 9000, duration: 9000,
isClosable: true, isClosable: true,
}); });
@ -64,26 +75,51 @@ function Login() {
}; };
return ( return (
<Flex height="100vh" background="teal.100" alignItems="center" justifyContent="center">
<Flex
height="100vh"
background="teal.100"
alignItems="center"
justifyContent="center"
>
<Flex direction="column" background="white" p={12} rounded={6}> <Flex direction="column" background="white" p={12} rounded={6}>
<Heading size="xl" mb={6}>SSR Covid Tracing</Heading>
<Heading size="lg" mb={4}>Login</Heading>
<Heading size="xl" mb={6}>
SSR Covid Tracing
</Heading>
<Heading size="lg" mb={4}>
Login
</Heading>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<FormControl mb={6}> <FormControl mb={6}>
<FormLabel>Email address</FormLabel> <FormLabel>Email address</FormLabel>
<Input type="email" colorScheme="teal" onChange={(event)=>setEmail(event.target.value)}/>
<Input
type="email"
colorScheme="teal"
onChange={event => setEmail(event.target.value)}
/>
</FormControl> </FormControl>
<FormControl mb={6}> <FormControl mb={6}>
<FormLabel>Password</FormLabel> <FormLabel>Password</FormLabel>
<Input type="password" colorScheme="teal" onChange={(event)=>setPassword(event.target.value)}/>
<Input
type="password"
colorScheme="teal"
onChange={event => setPassword(event.target.value)}
/>
</FormControl> </FormControl>
<Button mb={6} type="submit">Login!</Button>
<Button mb={6} type="submit">
Login!
</Button>
</form> </form>
<Divider mb={6} /> <Divider mb={6} />
<Button onClick={() => { history.push("/validate") }}>Get Validated!</Button>
<Button
onClick={() => {
history.push('/validate');
}}
>
Get Validated!
</Button>
</Flex> </Flex>
</Flex> </Flex>
); );
}
}
export default Login;
export default Login;

5
yarn.lock

@ -9601,6 +9601,11 @@ prepend-http@^1.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
prettier@2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d"
integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==
pretty-bytes@^5.3.0: pretty-bytes@^5.3.0:
version "5.6.0" version "5.6.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"

Loading…
Cancel
Save