More forms and backend NPE fix

This commit is contained in:
Amit Jakubowicz 2018-09-29 13:16:51 +02:00
parent 53dd50d098
commit 5533e0a995
9 changed files with 111 additions and 85 deletions

View File

@ -1,7 +1,7 @@
import {parse} from 'url'
import UserManager from './user'
import {Request, Response} from 'express'
import SessionManager, { SessionRequest } from './session'
import SessionManager, {Session, SessionRequest} from './session'
import {UserProperties} from './types'
let userManager, sessionManager
@ -83,7 +83,7 @@ const handleSignin = async (req: Request, res: Response) => {
const ip = req.ip.split('.').map(num => parseInt(num))
console.log('Got sign in request with params', JSON.stringify(params))
const session = await sessionManager.initiateSession({
const session: Session = await sessionManager.initiateSession({
hash: params.hash as string,
email: params.email as string,
ipAddress: ip,
@ -97,7 +97,6 @@ const handleSignin = async (req: Request, res: Response) => {
return
}
res.status(200)
// todo: invalidate session invite
res.setHeader('set-cookie', `__session=${session.hash}; Secure;`)
@ -126,7 +125,7 @@ const handlePostSession = async (req: Request, res: Response) => {
res.send('Could not find user')
return
}
await userManager.inviteUser(user)
await sessionManager.inviteUser(user)
res.status(200)
res.send('Invitation sent to email')
}

View File

@ -1,28 +0,0 @@
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}
.App-header {
background-color: #222;
height: 150px;
padding: 20px;
color: white;
}
.App-title {
font-size: 1.5em;
}
.App-intro {
font-size: large;
}
@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}

View File

@ -1,23 +1,15 @@
import * as React from 'react';
import {BrowserRouter as Router, Route} from 'react-router-dom';
import './App.css';
import CreateEvent from './CreateEvent';
import Login from './Login'
import logo from './logo.svg';
import RequestMagicLink from './RequestMagicLink'
class App extends React.Component {
public render() {
return (
<Router>
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo"/>
<h1 className="App-title">Welcome to React</h1>
</header>
<div className="App-intro">
<Route path="/login" component={Login}/>
<Route path="/post" component={CreateEvent}/>
</div>
<div>
<Route path="/login" component={RequestMagicLink}/>
<Route path="/post" component={CreateEvent}/>
</div>
</Router>
);

View File

@ -1,34 +0,0 @@
import axios from 'axios'
import {Field, FieldProps, Form, Formik} from 'formik';
import * as React from 'react';
const submitLogin = (loginRequest: LoginRequest) => {
axios.post('/api/session', loginRequest)
}
interface LoginRequest {
email: string;
}
const Login = () => (
<div>
<h1>Login</h1>
<div>
Please enter your email
</div>
<Formik onSubmit={submitLogin} initialValues={{email: ''}}>
{
() => (
<Form>
<Field name="email">
{
({ field }: FieldProps<string>) => <input {...field} />
}
</Field>
</Form>
)
}
</Formik>
</div>
)
export default Login

View File

@ -0,0 +1,95 @@
import axios from 'axios'
import {Field, FieldProps, Form, Formik, FormikErrors, FormikProps} from 'formik';
import * as React from 'react';
import {RouteComponentProps, withRouter} from "react-router";
import styled from 'styled-components';
const submitRequestToken = (loginRequest: SessionRequest) => {
axios.post('/api/session', loginRequest)
}
interface SessionRequest {
email: string;
}
interface Props extends RouteComponentProps {
}
class RequestMagicLink extends React.Component<Props, {}> {
handleValidate(values: SessionRequest): FormikErrors<SessionRequest> {
const errors: FormikErrors<SessionRequest> = {};
// get a proper validator for this
if (!(values && values.email && values.email.includes('@'))){
errors.email = 'Must include valid email address'
}
return errors
}
handleSubmit = async (values: SessionRequest) => {
this.setState({
loading: true,
})
let response
try {
response = await axios.post('/api/signin', values)
} catch (e) {
this.setState({
error: e
})
return
} finally {
this.setState({
loading: false
})
}
if (response.status === 200) {
this.setState({
error: null,
invitationSent: true,
})
}
}
render() {
return (
<div>
<h1>Login</h1>
<MessageContainer>
In order to just view the calendar you don't need to log in, you can simply go back to the calendar and browse
the events. You only need a login if you have an event you would like to publish or manage. If you already have
registered, simply enter your email below and you will get a magic link per email. Following the magic link will
log you into this page. No password necessary.
</MessageContainer>
<Formik onSubmit={submitRequestToken} initialValues={{email: ''}} validateOnBlur={true} validate={this.handleValidate}>
{
(formikProps: FormikProps<SessionRequest>) => (
<Form>
<Field name="email">
{
({ field }: FieldProps<string>) => <input type="email" {...field} />
}
</Field>
<Button disabled={!formikProps.isValid} type="submit">Request magic link</Button>
</Form>
)
}
</Formik>
</div>
)
}
}
const MessageContainer = styled.div`
max-width: 600px;
margin-bottom: 24px;
`
const Button = styled.button`
&[disabled] {
cursor: not-allowed;
}
`
export default withRouter(RequestMagicLink)

View File

@ -0,0 +1,7 @@
import * as React from 'react';
export default class Signup extends React.Component {
render() {
return <div>signup</div>
}
}

View File

@ -1,5 +0,0 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}

View File

@ -1,7 +1,6 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(

View File

@ -15,6 +15,7 @@
"member-access": false,
"object-literal-sort-keys":false,
"no-console": false,
"interface-name" : false
"interface-name" : false,
"no-empty-interface" : false
}
}