Skip to content

Instantly share code, notes, and snippets.

@krnbr
Created August 13, 2019 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krnbr/eee5b45275ed53e9657b6041015de30b to your computer and use it in GitHub Desktop.
Save krnbr/eee5b45275ed53e9657b6041015de30b to your computer and use it in GitHub Desktop.
import React, {useEffect, useLayoutEffect, useRef, useState} from 'react';
import {Button,CircularProgress,CssBaseline,TextField,Grid,Container,Theme,makeStyles,Box,FormHelperText,SnackbarContent,Snackbar,Icon,IconButton} from '@material-ui/core';
/*import Link from '@material-ui/core/Link';*/
/*import {makeStyles} from '@material-ui/core/styles';*/
import defaultTheme from '../src/theme';
import {ThemeProvider} from '@material-ui/styles';
import Logo from "../src/components/logo";
import {PasswordDto, RecaptchaDto, SignInDto, UserDto} from "../models/SignInDto";
import {NextPage} from "next";
import '../styles/signin.scss';
import Link from 'next/link';
import ReCAPTCHA from "react-google-recaptcha";
import Router from 'next/router'
import clsx from 'clsx';
import CloseIcon from '@material-ui/icons/Close';
const useStyles = makeStyles((theme: Theme) => {
return {
body: {
backgroundImage: "url('/static/images/escheresque.png')",
backgroundRepeat:'repeat'
},
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: defaultTheme.palette.secondary.main ? defaultTheme.palette.secondary.main : theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
icon: {
fontSize: 20,
},
iconVariant: {
opacity: 0.9,
marginRight: theme.spacing(1),
},
error: {
backgroundColor: "#ff6e63",
},
message: {
display: 'flex',
alignItems: 'center',
},
};
});
let signInDto: SignInDto = new SignInDto();
let userDto: UserDto = signInDto.username;
let passwordDto: PasswordDto = signInDto.password;
let recaptcha: RecaptchaDto = signInDto.recaptcha;
const useIsomorphicLayoutEffect =
typeof window !== 'undefined' ? useLayoutEffect : useEffect;
const Login: NextPage = (props:any) => {
const usernameInputRef = useRef({value:""});
const passwordInputRef = useRef({value:""});
const recaptchaInputRef:any = useRef({});
const [formData, setFormData] = useState<SignInDto>(signInDto);
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
useIsomorphicLayoutEffect(()=> {
document!.body.classList.add('signin');
console.log('I am about to render signin page!');
setFormData({...signInDto});
},[]);
useEffect(() => {
return () => {
document!.body.classList.remove('signin');
console.log('will unmount signin page!');
}
}, []);
function handleClose(event, reason) {
setOpen(false);
}
// React.SyntheticEvent
const handleSubmit = async (event) => {
if (event) event.preventDefault();
usernameValueCheck(usernameInputRef.current!.value);
passwordValueCheck(passwordInputRef.current!.value);
console.log("recaptchaInputRef.current!.value "+ recaptchaInputRef.current.getValue());
recaptchaValueCheck(recaptchaInputRef.current.getValue());
if(formData.username.valid && formData.password.valid && formData.recaptcha.valid){
setLoading(true);
// TODO fetch
console.log("requesting ");
console.log(recaptchaInputRef.current.getValue());
console.log("requesting ---");
const response = await fetch("/sign-in", {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username:usernameInputRef.current!.value,
password:passwordInputRef.current!.value,
recaptchaResponse:recaptchaInputRef.current.getValue(),
})
});
if(response.ok) {
const json = await response.json();
console.log("response " + JSON.stringify(json));
setLoading(false);
// TODO redirect appropriate
Router.push('/');
} else {
const json = await response.json();
console.log("error response " + JSON.stringify(json));
setLoading(false);
setOpen(true);
recaptchaInputRef.current.reset();
}
}
/*setIsSubmitting(true);
setErrors(validate(values));*/
};
const onChange = (value) => {
console.log("Captcha value:", value);
recaptchaValueCheck(value);
}
const onExpired = () => {
console.log("Captcha expired value:", recaptchaInputRef.current.getValue());
recaptchaValueCheck(recaptchaInputRef.current.getValue());
}
const handleChange = (event) => {
if (event) event.preventDefault();
console.log("val of " + JSON.stringify(event.target.id));
if (event.target.id === formData.username.id) {
if (event.target.value.match("^[a-zA-Z0-9]+$")) {
console.log('username changed value');
userDto.valid = true;
} else {
console.log('username changed value and doesnot matches!!');
userDto.valid = false;
}
userDto.value = event.target.value;
setFormData({
...signInDto,
username: userDto
});
//setFormData(signInDto);
} else if (event.target.id === formData.password.id) {
passwordValueCheck(event.target.value);
}
};
const usernameOnFocus = (event) => {
usernameValueCheck(event.target.value);
}
const usernameValueCheck = (value) => {
if (value.match("^[a-zA-Z0-9]+$")) {
console.log('username changed value');
userDto.valid = true;
} else {
console.log('username changed value and doesnot matches!!');
userDto.valid = false;
}
userDto.value = value;
setFormData({
...signInDto,
username: userDto
});
}
const passwordOnFocus = (event) => {
passwordValueCheck(event.target.value);
}
const passwordValueCheck = (value) => {
if (value && (value !== null || value !== "")) {
console.log('password changed value');
passwordDto.valid = true;
} else {
console.log('password changed value and does not matches!!');
passwordDto.valid = false;
}
passwordDto.value = value;
setFormData({
...signInDto,
password: passwordDto
});
}
const recaptchaValueCheck = (value) => {
if (value && (value !== null || value.trim() !== "")) {
console.log('recaptcha changed value');
recaptcha.valid = true;
} else {
console.log('recaptcha changed value and does not matches!!');
recaptcha.valid = false;
}
recaptcha.value = value;
setFormData({
...signInDto,
recaptcha: recaptcha
});
}
const classes = useStyles(props);
return (
<React.Fragment>
<div id="color-overlay"></div>
<Container component="main" maxWidth="xs">
{/*<Logo style={{marginTop: 50, marginBottom: -20, marginLeft: "auto", marginRight: "auto", display: "block"}}/>*/}
<Box boxShadow={3} padding="25px" marginTop="15px" height="100%" bgcolor={"#e8e8e8"}>
<CssBaseline/>
<Logo style={{
marginTop: 20,
marginBottom: -45,
marginLeft: "auto",
marginRight: "auto",
display: "block"
}}/>
{/*<Typography component="h1" variant="h5">
Sign in
</Typography>*/}
<div className={classes.paper}>
<form className={classes.form} noValidate autoComplete="none" onSubmit={e => handleSubmit(e)}>
<input autoComplete="false" name="hidden" type="text" style={{display: 'none'}}/>
<ThemeProvider theme={defaultTheme}>
<TextField
margin="normal"
required
fullWidth
id="username"
label="Username"
name="username"
autoComplete="off"
autoFocus
/*onFocus={e => usernameOnFocus(e)}*/
onChange={e => handleChange(e)}
error={!formData.username.valid}
helperText={
!formData.username.valid ?
formData.username.requiredMessage : ''
}
inputRef={usernameInputRef}
/>
<TextField
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
onChange={e => handleChange(e)}
onFocus={e => passwordOnFocus(e)}
error={!formData.password.valid}
helperText={
!formData.password.valid ?
formData.password.requiredMessage : ''
}
inputRef={passwordInputRef}
/>
{/*not required as not going to support now*/}
{/*<FormControlLabel
control={<Checkbox value="remember" color="primary"/>}
label="Remember me"
color="#0099f8"
style={{marginTop: 20}}
/>*/}
<div id={"captchaContainer"} style={
{
display:"table",
margin: "0 auto",
marginTop:25,
marginBottom: 15,
position:'relative',
}
}>
<ReCAPTCHA
ref={recaptchaInputRef}
sitekey={props.recaptchaKey}
onChange={ onChange }
onExpired={ onExpired }
/>
{
!formData.recaptcha.valid?
<FormHelperText error={true} > {/*style={{display:'contents', position:'absolute'}}*/}
Human verification required
</FormHelperText>:''
}
</div>
<div>
{/*<Snackbar open={true}>
<SnackbarContent color={"red"} message={"Unable to signin with provided credentials!!"}>
</SnackbarContent>
</Snackbar>*/}
{/*<Snackbar
open={open}
onClose={handleClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
autoHideDuration={20000}
>*/}
{ open &&
<SnackbarContent
className={classes.error}
aria-describedby="client-snackbar"
message={
<span id="client-snackbar" className={classes.message}>
<Icon className={clsx(classes.icon, classes.iconVariant)} />
{"Wrong credentials!!"}
</span>
}
action={[
<IconButton key="close" aria-label="close" color="inherit" onClick={(e)=>handleClose(e,'')} >
<CloseIcon className={classes.icon} />
</IconButton>,
]}
/>
}
{/*</Snackbar>*/}
</div>
<div style={{position:'relative'}}>
<Button
type="submit"
fullWidth
variant="contained"
color="secondary"
className={classes.submit}
style={{marginTop: 30}}
disabled={loading}
>
Sign In
</Button>
{ loading && <CircularProgress size={24} className="circularProgressButton" color="primary" />}
</div>
</ThemeProvider>
<Grid container>
<Grid item xs>
{/*<Link href="" variant="body2">
Forgot password?
</Link>*/}
<Link href="/" as={`/`}>
<a className={"anchor"}>Forgot password?</a>
</Link>
</Grid>
<Grid item>
{/*<mLink href="" variant="body2">
{"Don't have an account? Sign Up"}
</mLink>*/}
<Link href={{pathname: '/register', query: {recaptchaKey: props.recaptchaKey}}} as="/register">
<a className={"anchor"}>Don't have an account? Sign Up</a>
</Link>
</Grid>
</Grid>
</form>
</div>
</Box>
</Container>
</React.Fragment>
);
};
Login.getInitialProps = async function(context) {
const { recaptchaKey } = context.query;
return { recaptchaKey };
};
export default Login;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment