UI: add auth flow and related errors

This commit is contained in:
41666 2019-03-19 20:26:47 -05:00
parent ff67bc3f1b
commit bbb34f1771
6 changed files with 226 additions and 74 deletions

View file

@ -10,12 +10,13 @@ export const Overlay = styled.div`
bottom: 0;
left: 0;
right: 0;
z-index: -1;
z-index: -10;
background-image: radial-gradient(circle, var(--c-dark), var(--c-dark) 1px, transparent 1px, transparent);
background-size: 27px 27px;
`
const ResponsiveSplitter = styled.div`
z-index: -1;
display: flex;
align-items: center;
justify-content: center;
@ -59,86 +60,25 @@ export default class CustomErrorPage extends React.Component {
return { statusCode }
}
render404 () {
return <div>
<Overlay />
<ResponsiveSplitter>
<div>
<Code>404</Code>
</div>
<div>
<section>
This page is in another castle.
</section>
<JapaneseFlair>お探しのページは見つかりませんでした</JapaneseFlair>
</div>
</ResponsiveSplitter>
</div>
}
render403 = () => this.out('403', `You weren't allowed to access this.`, 'あなたはこの点に合格しないかもしれません')
render404 = () => this.out('404', 'This page is in another castle.', 'お探しのページは見つかりませんでした')
render500 = () => this.out('500', `The server doesn't like you right now. Feed it a cookie.`, 'クッキーを送ってください〜 クッキーを送ってください〜')
renderDefault = () => this.out('Oops', 'Something went bad. How could this happen?', 'おねがい?')
renderServer = () => this.out('Oops.', 'Server was unhappy about this render. Try reloading or changing page.', 'クッキーを送ってください〜')
renderAuthExpired = () => this.out('Woah.', 'That magic login link was expired.', 'What are you trying to do?')
render403 () {
out (code, description, flair) {
return <div>
<Overlay />
<ResponsiveSplitter>
<div>
<Code>403</Code>
<Code>{code}</Code>
</div>
<div>
<section>
You weren't allowed to access this.
{description}
</section>
<JapaneseFlair>あなたはこの点に合格しないかもしれません</JapaneseFlair>
</div>
</ResponsiveSplitter>
</div>
}
render500 () {
return <div>
<Overlay />
<ResponsiveSplitter>
<div>
<Code>500</Code>
</div>
<div>
<section>
The server doesn't like you right now. Feed it a cookie.
</section>
<JapaneseFlair>クッキーを送ってください クッキーを送ってください</JapaneseFlair>
</div>
</ResponsiveSplitter>
</div>
}
renderDefault () {
return <div>
<Overlay />
<ResponsiveSplitter>
<div>
<Code>Oops.</Code>
</div>
<div>
<section>
Something went bad. How could this happen?
</section>
<JapaneseFlair>おねがい</JapaneseFlair>
</div>
</ResponsiveSplitter>
</div>
}
renderServer () {
return <div>
<Overlay />
<ResponsiveSplitter>
<div>
<Code>Oops.</Code>
</div>
<div>
<section>
Server was unhappy about this render. Try reloading or changing page.
</section>
<JapaneseFlair>クッキーを送ってください</JapaneseFlair>
<JapaneseFlair>{flair}</JapaneseFlair>
</div>
</ResponsiveSplitter>
</div>
@ -147,7 +87,8 @@ export default class CustomErrorPage extends React.Component {
handlers = {
403: this.render403,
404: this.render404,
500: this.render500
500: this.render500,
1001: this.renderAuthExpired
}
render () {

3
ui/pages/auth/expired.js Normal file
View file

@ -0,0 +1,3 @@
import ErrorPage from '../_error'
export default (props) => <ErrorPage {...props} statusCode={1001} />

125
ui/pages/auth/login.js Normal file
View file

@ -0,0 +1,125 @@
// @flow
import * as React from 'react'
import styled from 'styled-components'
import MediaQuery from '../../kit/media'
import DiscordButton from '../../components/discord-button'
import RPC from '../../config/rpc'
import redirect from '../../lib/redirect'
type AuthLoginState = {
humanCode: string,
waiting: boolean
}
const Wrapper = styled.div`
display: flex;
justify-content: center;
padding-top: 3em;
${() => MediaQuery({
md: `
padding-top: 0;
align-items: center;
min-height: 80vh;
`
})}
`
const Line = styled.div`
height: 1px;
background-color: var(--c-9);
margin: 1em 0.3em;
`
const SecretCode = styled.input`
background-color: transparent;
border: 0;
padding: 1em;
color: var(--c-9);
margin: 0.5rem 0;
width: 100%;
font-size: 0.9em;
appearance: none;
transition: all 0.3s ease-in-out;
&:focus, &:active, &:hover {
background-color: var(--c-3);
}
&:focus, &:active {
& ::placeholder {
color: transparent;
}
}
& ::placeholder {
transition: all 0.3s ease-in-out;
color: var(--c-7);
text-align: center;
}
`
const HiderButton = styled.button`
appearance: none;
display: block;
cursor: pointer;
width: 100%;
background-color: var(--c-3);
color: var(--c-white);
border: none;
padding: 1em;
font-size: 0.9em;
transition: all 0.3s ease-in-out;
&[disabled] {
cursor: default;
opacity: 0;
pointer-events: none;
}
`
export default class AuthLogin extends React.Component<{}, AuthLoginState> {
state = {
humanCode: '',
waiting: false
}
static async getInitialProps (ctx, rpc) {
if (ctx.user != null) {
redirect(ctx, '/')
}
}
onChange = (event: any) => {
this.setState({ humanCode: event.target.value })
}
onSubmit = async () => {
this.setState({ waiting: true })
try {
const result = await RPC.checkAuthChallenge(this.state.humanCode)
if (result === true) {
redirect(null, '/')
}
} finally {
this.setState({ waiting: false })
}
}
render () {
return <Wrapper>
<div>
<DiscordButton href='/api/auth/redirect'>Sign in with Discord</DiscordButton>
<Line />
<div>
<i>Or, send a DM to <b>roleypoly</b>#3712 saying: login</i>
</div>
<div>
<SecretCode placeholder='click to enter super secret code' onChange={this.onChange} value={this.state.humanCode} />
<HiderButton onClick={this.onSubmit} disabled={this.state.humanCode === ''}>{
(this.state.waiting) ? 'One sec...' : 'Submit Code →'
}</HiderButton>
</div>
</div>
</Wrapper>
}
}