diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 76fe12bf..f234fcd0 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -74,6 +74,10 @@ figure { text-align: center; } +p { + margin-bottom: 1em; +} + #mnml { display: grid; grid-template-columns: minmax(min-content, 1fr) 8fr 1fr; @@ -189,11 +193,28 @@ button[disabled] { LOGIN */ -.login { - width: 50%; - display: flex; - flex-flow: column; - margin-bottom: 2em; +.welcome { + .highlight { + color: black; + background: @white; + border: 1px solid @white; + } + + .login { + width: 50%; + display: flex; + flex-flow: column; + margin-bottom: 2em; + } + + .options { + width: 50%; + display: flex; + flex-flow: row; + button { + flex: 1; + } + } h2 { margin-bottom: 0.5em; diff --git a/client/assets/styles/styles.mobile.css b/client/assets/styles/styles.mobile.css index 263761ff..c0db0c18 100644 --- a/client/assets/styles/styles.mobile.css +++ b/client/assets/styles/styles.mobile.css @@ -53,10 +53,19 @@ padding: 0 0.5em; } - .login { + .welcome .login { width: 100%; } + .welcome .options { + width: 100%; + flex-flow: row wrap; + } + + .welcome .options button { + flex: 1 0 50%; + } + .timer-container { margin: 0.5em 0 0 0; } diff --git a/client/index.html b/client/index.html index 88515382..453c4706 100644 --- a/client/index.html +++ b/client/index.html @@ -16,7 +16,10 @@ - + diff --git a/client/src/components/login.jsx b/client/src/components/login.jsx deleted file mode 100644 index 6b7eefd3..00000000 --- a/client/src/components/login.jsx +++ /dev/null @@ -1,170 +0,0 @@ -// eslint-disable-next-line -const preact = require('preact'); -const { Component } = require('preact') -const { connect } = require('preact-redux'); -const linkState = require('linkstate').default; - -const { postData, errorToast } = require('../utils'); - -const addState = connect( - (state) => { - const { - ws - } = state; - function submitLogin(name, password) { - postData('/account/login', { name, password }) - .then(res => res.json()) - .then(data => { - if (data.error) return errorToast(data.error); - console.log(data.response); - ws.connect(); - }) - .catch(error => errorToast(error)); - } - - function submitRegister(name, password, code) { - postData('/account/register', { name, password, code }) - .then(res => res.json()) - .then(data => { - if (data.error) return errorToast(data.error); - console.log(data.response); - ws.connect(); - }) - .catch(error => errorToast(error)); - } - - return { - submitLogin, - submitRegister, - } - }, -); - -class Login extends Component { - constructor(props) { - super(props); - - this.state = { - login: { name: '', password: '', code: ''}, - register: { name: '', password: '', confirm: '', code: ''}, - }; - - this.loginSubmit = this.loginSubmit.bind(this); - this.registerSubmit = this.registerSubmit.bind(this); - } - - loginSubmit(event) { - event.preventDefault(); - console.log(this.state); - this.props.submitLogin(this.state.login.name, this.state.login.password); - this.setState({ login: { name: '', password: '' }}); - } - - registerSubmit(event) { - event.preventDefault(); - this.props.submitRegister(this.state.register.name, this.state.register.password, this.state.register.code); - this.setState({ register: { name: '', password: '', confirm: '', code: ''}}); - } - - render() { - const registerConfirm = () => - this.state.register.password === this.state.register.confirm; - - const loginDisabled = () => { - const { password, name } = this.state.login; - return !(password && name); - } - - const registerDisabled = () => { - const { password, name, code } = this.state.register; - return !(registerConfirm() && password && name && code); - } - - return ( -
-

mnml.gg

-
-
mnml is an abstract turn based strategy game
-
free to play
-
no email required
-
-
-

Login

- - - - - -
-
-

Register

- - - - - - - - - - -
-
- ); - } -} - -module.exports = addState(Login); diff --git a/client/src/components/main.jsx b/client/src/components/main.jsx index 44948fe2..57abab03 100644 --- a/client/src/components/main.jsx +++ b/client/src/components/main.jsx @@ -2,7 +2,7 @@ const preact = require('preact'); const { connect } = require('preact-redux'); -const Login = require('./login'); +const Welcome = require('./welcome'); const Game = require('./game'); const Instance = require('./instance.component'); const Team = require('./team'); @@ -25,7 +25,7 @@ function Main(props) { } = props; if (!account) { - return ; + return ; } if (game) { diff --git a/client/src/components/welcome.about.jsx b/client/src/components/welcome.about.jsx new file mode 100644 index 00000000..0f33b942 --- /dev/null +++ b/client/src/components/welcome.about.jsx @@ -0,0 +1,69 @@ +// eslint-disable-next-line +const preact = require('preact'); +const { Component } = require('preact') +const { connect } = require('preact-redux'); +const linkState = require('linkstate').default; + +const { postData, errorToast, infoToast } = require('../utils'); + +const addState = connect( + (state) => { + const { + ws + } = state; + + function submitRegister(name, password, code) { + postData('/account/register', { name, password, code }) + .then(res => res.json()) + .then(data => { + if (data.error) return errorToast(data.error); + infoToast(data.message); + ws.connect(); + }) + .catch(error => errorToast(error)); + } + + return { + submitRegister, + } + }, +); + +function Register(args) { + const { + submitRegister, + navRegister, + } = args; + + return ( + + ); +} + +module.exports = addState(Register); diff --git a/client/src/components/welcome.help.jsx b/client/src/components/welcome.help.jsx new file mode 100644 index 00000000..b864e6a0 --- /dev/null +++ b/client/src/components/welcome.help.jsx @@ -0,0 +1,91 @@ +// eslint-disable-next-line +const preact = require('preact'); +const { Component } = require('preact') +const { connect } = require('preact-redux'); +const linkState = require('linkstate').default; + +const { postData, errorToast, infoToast } = require('../utils'); + +const addState = connect( + (state) => { + const { + ws + } = state; + + function submitRecover(email) { + postData('/account/recover', { email }) + .then(res => res.json()) + .then(data => { + if (data.error) return errorToast(data.error); + infoToast(data.message); + }) + .catch(error => errorToast(error)); + } + + return { + submitRecover, + } + }, +); + +const EMAIL_SUBJECT = name => ` +account support: ${name || 'CHANGEME'} +`; + +const EMAIL_BODY = ` +--- +include some details regarding your account. ie. +- account name +- construct names +--- +`; + +function Register(args) { + const { + submitRecover, + } = args; + + const { email } = this.state; + + const buttonSubmit = (event) => { + event.preventDefault(); + submitRecover(email); + // this.setState({ email: '' }); + }; + + const buttonDisabled = () => { + return !email; + }; + + const supportLink = encodeURI(`mailto:humans@mnml.gg?subject=${EMAIL_SUBJECT(email)}&body=${EMAIL_BODY}`); + + return ( + + ); +} + +module.exports = addState(Register); diff --git a/client/src/components/welcome.jsx b/client/src/components/welcome.jsx new file mode 100644 index 00000000..27575d98 --- /dev/null +++ b/client/src/components/welcome.jsx @@ -0,0 +1,61 @@ +// eslint-disable-next-line +const preact = require('preact'); + +const Login = require('./welcome.login'); +const Register = require('./welcome.register'); +const Help = require('./welcome.help'); +const About = require('./welcome.about'); + +function Welcome() { + const page = this.state.page || 'login'; + + const navRegister = () => this.setState({ page: 'register' }); + const pageEl = () => { + if (page === 'login') return ; + if (page === 'register') return ; + if (page === 'about') return ; + if (page === 'help') return ; + return false; + }; + + return ( +
+

mnml.gg

+ +
+ + + + +
+ {pageEl()} +
+ ); +} + +module.exports = Welcome; diff --git a/client/src/components/welcome.login.jsx b/client/src/components/welcome.login.jsx new file mode 100644 index 00000000..aa65f20d --- /dev/null +++ b/client/src/components/welcome.login.jsx @@ -0,0 +1,80 @@ +// eslint-disable-next-line +const preact = require('preact'); +const { Component } = require('preact') +const { connect } = require('preact-redux'); +const linkState = require('linkstate').default; + +const { postData, errorToast } = require('../utils'); + +const addState = connect( + (state) => { + const { + ws + } = state; + function submitLogin(name, password) { + postData('/account/login', { name, password }) + .then(res => res.json()) + .then(data => { + if (data.error) return errorToast(data.error); + console.log(data.message); + ws.connect(); + }) + .catch(error => errorToast(error)); + } + + return { + submitLogin, + } + }, +); + + +function Login(args) { + const { + submitLogin, + } = args; + + const { password, name } = this.state; + + const loginSubmit = (event) => { + event.preventDefault(); + submitLogin(name, password); + this.setState({ name: '', password: '' }); + }; + + const loginDisabled = () => { + return !(password && name); + }; + + return ( + + ); +} + +module.exports = addState(Login); diff --git a/client/src/components/welcome.register.jsx b/client/src/components/welcome.register.jsx new file mode 100644 index 00000000..7051a8ce --- /dev/null +++ b/client/src/components/welcome.register.jsx @@ -0,0 +1,96 @@ +// eslint-disable-next-line +const preact = require('preact'); +const { Component } = require('preact') +const { connect } = require('preact-redux'); +const linkState = require('linkstate').default; + +const { postData, errorToast, infoToast } = require('../utils'); + +const addState = connect( + (state) => { + const { + ws + } = state; + + function submitRegister(name, password, code) { + postData('/account/register', { name, password, code }) + .then(res => res.json()) + .then(data => { + if (data.error) return errorToast(data.error); + infoToast(data.message); + ws.connect(); + }) + .catch(error => errorToast(error)); + } + + return { + submitRegister, + } + }, +); + +function Register(args) { + const { + submitRegister, + } = args; + + const { password, confirm, name, code } = this.state; + + const registerSubmit = (event) => { + event.preventDefault(); + submitRegister(name, password, code); + // this.setState({ name: '', password: '', confirm: '', code: ''}); + } + + const registerConfirm = () => + password === confirm; + + const registerDisabled = () => { + return !(registerConfirm() && password && name && code); + } + + return ( + + ); +} + +module.exports = addState(Register); diff --git a/ops/migrations/20180913000513_create_accounts.js b/ops/migrations/20180913000513_create_accounts.js index 3184ff08..17eddca3 100755 --- a/ops/migrations/20180913000513_create_accounts.js +++ b/ops/migrations/20180913000513_create_accounts.js @@ -9,6 +9,7 @@ exports.up = async knex => { table.string('token', 64) .notNullable() .index(); + table.timestamp('token_expiry').notNullable(); table.bigInteger('balance') diff --git a/server/src/mail.rs b/server/src/mail.rs index 00d3950c..9e7813ad 100644 --- a/server/src/mail.rs +++ b/server/src/mail.rs @@ -42,10 +42,13 @@ pub enum Mail { fn recover(email: &String, name: &String, token: &String) -> SendableEmail { let body = format!("{:}, the link below will recover your account. -please change your password immediately in the account page +please change your password immediately in the account page. +this link will expire in 48 hours or once used. + http://mnml.gg/api/account/recover?recover_token={:} -glhf", name, token); +glhf +--mnml", name, token); Email::builder() .from("machines@mnml.gg") @@ -62,7 +65,8 @@ fn confirm(email: &String, name: &String, token: &String) -> SendableEmail { please click the link below to confirm your email http://mnml.gg/api/account/email/confirm?confirm_token={:} -glhf", name, token); +glhf +--mnml", name, token); Email::builder() .from("machines@mnml.gg")