added new create account screen

This commit is contained in:
Roland Osborne 2022-08-04 22:54:15 -07:00
parent f10e10d525
commit 78fe7f3cb2
10 changed files with 263 additions and 13 deletions

View File

@ -1,5 +1,4 @@
import styled from 'styled-components';
import Colors from 'constants/Colors';
export const AppWrapper = styled.div`
position: absolute;

View File

@ -4,6 +4,7 @@ import { AppContext } from 'context/AppContext';
import { ViewportContext } from 'context/ViewportContext';
import { AccessWrapper } from './Access.styled';
import { Login } from './login/Login';
import { CreateAccount } from './createAccount/CreateAccount';
import login from 'images/login.png'
@ -19,12 +20,15 @@ export function Access({ mode }) {
navigate('/session');
}
}
}, [app]);
}, [app, navigate]);
const Prompt = () => {
if (mode === 'login') {
return <Login />
}
if (mode === 'create') {
return <CreateAccount />
}
return <></>
}

View File

@ -0,0 +1,77 @@
import { Button, Modal, Form, Input } from 'antd';
import { SettingOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
import { CreateAccountWrapper } from './CreateAccount.styled';
import { useCreateAccount } from './useCreateAccount.hook';
export function CreateAccount() {
const { state, actions } = useCreateAccount();
const create = async () => {
try {
await actions.onCreateAccount();
}
catch(err) {
Modal.error({
title: 'Create Account Error',
content: 'Please check with you administrator.',
});
}
}
const keyDown = (e) => {
if (e.key === 'Enter') {
create()
}
}
return (
<CreateAccountWrapper>
<div class="app-title">
<span>Databag</span>
<div class="settings" onClick={() => actions.onSettings()}>
<SettingOutlined />
</div>
</div>
<div class="form-title">Create Account</div>
<div class="form-form">
<Form name="basic" wrapperCol={{ span: 24, }}>
<Form.Item name="username" validateStatus={state.validateStatus} help={state.help}>
<Input placeholder="Username" spellCheck="false" onChange={(e) => actions.setUsername(e.target.value)}
autocomplete="username" autocapitalize="none" onKeyDown={(e) => keyDown(e)} prefix={<UserOutlined />} />
</Form.Item>
<div class="form-space"></div>
<Form.Item name="password">
<Input.Password placeholder="Password" spellCheck="false" onChange={(e) => actions.setPassword(e.target.value)}
autocomplete="new-password" onKeyDown={(e) => keyDown(e)} prefix={<LockOutlined />} />
</Form.Item>
<Form.Item name="confirm">
<Input.Password placeholder="Confirm Password" spellCheck="false" onChange={(e) => actions.setConfirm(e.target.value)}
autocomplete="new-password" onKeyDown={(e) => keyDown(e)} prefix={<LockOutlined />} />
</Form.Item>
<div class="form-button">
<div class="form-create">
<Button type="primary" block onClick={create} disabled={ actions.isDisabled()}
loading={state.busy}>
Create Account
</Button>
</div>
</div>
<div class="form-button">
<Button type="link" block onClick={(e) => actions.onLogin()}>
Account Login
</Button>
</div>
</Form>
</div>
</CreateAccountWrapper>
);
};

View File

@ -0,0 +1,62 @@
import styled from 'styled-components';
import Colors from 'constants/Colors';
export const CreateAccountWrapper = styled.div`
max-width: 400px;
width: 90%;
height: 90%;
display: flex;
flex-direction: column;
.app-title {
font-size: 24px;
display: flex;
align-items: flex-start;
justify-content: center;
flex: 1;
color: ${Colors.grey};
.settings {
color: ${Colors.grey};
position: absolute;
top: 0px;
right: 0px;
font-size: 20px;
cursor: pointer;
margin: 16px;
}
}
.form-title {
font-size: 32px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
flex: 1;
}
.form-form {
flex: 2;
.form-space {
height: 16px;
}
.form-button {
display: flex;
align-items: center;
justify-content: center;
.form-login {
width: 50%;
}
}
}
.form-submit {
background-color: #444444;
}
`;

View File

@ -0,0 +1,111 @@
import { useContext, useState, useEffect, useRef } from 'react';
import { AppContext } from 'context/AppContext';
import { useNavigate, useLocation } from "react-router-dom";
export function useCreateAccount() {
const [checked, setChecked] = useState(true);
const [state, setState] = useState({
username: '',
password: '',
confirm: '',
busy: false,
validatetatus: 'success',
help: '',
});
const navigate = useNavigate();
const { search } = useLocation();
const app = useContext(AppContext);
const debounce = useRef(null);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
const usernameSet = (name) => {
setChecked(false)
clearTimeout(debounce.current)
debounce.current = setTimeout(async () => {
if (app.actions?.username && name !== '') {
try {
let valid = await app.actions.username(name, state.token)
if (!valid) {
updateState({ validateStatus: 'error', help: 'Username is not available' })
}
else {
updateState({ validateStatus: 'success', help: '' })
}
setChecked(true)
}
catch(err) {
console.log(err);
}
}
else {
updateState({ validateStatus: 'success', help: '' });
setChecked(true);
}
}, 500)
}
const actions = {
setUsername: (username) => {
updateState({ username });
usernameSet(username);
},
setPassword: (password) => {
updateState({ password });
},
setConfirm: (confirm) => {
updateState({ confirm });
},
isDisabled: () => {
if (state.username === '' || state.password === '' || state.password !== state.confirm || !checked ||
state.validateStatus === 'error') {
return true
}
return false
},
onSettings: () => {
navigate('/admin');
},
onCreateAccount: async () => {
if (!state.busy && state.username !== '' && state.password !== '' && state.password === state.confirm) {
updateState({ busy: true })
try {
await app.actions.create(state.username, state.password)
}
catch (err) {
console.log(err);
updateState({ busy: false })
throw new Error('create failed: check with your admin');
}
updateState({ busy: false })
}
},
onLogin: () => {
navigate('/login');
},
};
useEffect(() => {
if (app) {
if (app.state) {
if (app.state.access) {
navigate('/session')
}
}
else {
let params = new URLSearchParams(search);
let token = params.get("add");
if (token) {
updateState({ token });
}
}
}
}, [app, navigate, search])
return { state, actions };
}

View File

@ -1,7 +1,6 @@
import React, { useState } from 'react';
import { Button, Modal, Form, Input } from 'antd';
import { SettingOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
import { LoginWrapper, SubmitButton } from './Login.styled';
import { LoginWrapper } from './Login.styled';
import { useLogin } from './useLogin.hook';
export function Login() {
@ -40,12 +39,12 @@ export function Login() {
<Form.Item name="username">
<Input placeholder="Username" spellCheck="false" onChange={(e) => actions.setUsername(e.target.value)}
autocapitalize="none" onKeyDown={(e) => keyDown(e)} prefix={<UserOutlined />} />
autocomplete="username" autocapitalize="none" onKeyDown={(e) => keyDown(e)} prefix={<UserOutlined />} />
</Form.Item>
<Form.Item name="password">
<Input.Password placeholder="Password" spellCheck="false" onChange={(e) => actions.setPassword(e.target.value)}
onKeyDown={(e) => keyDown(e)} prefix={<LockOutlined />} />
autocomplete="current-password" onKeyDown={(e) => keyDown(e)} prefix={<LockOutlined />} />
</Form.Item>
<div class="form-button">

View File

@ -1,6 +1,6 @@
import { useContext, useState, useEffect } from 'react';
import { AppContext } from 'context/AppContext';
import { useNavigate, useLocation, useParams } from "react-router-dom";
import { useNavigate, useLocation } from "react-router-dom";
export function useLogin() {
@ -37,7 +37,7 @@ export function useLogin() {
navigate('/admin');
},
onLogin: async () => {
if (!state.busy && state.username != '' && state.password != '') {
if (!state.busy && state.username !== '' && state.password !== '') {
updateState({ busy: true })
try {
await app.actions.login(state.username, state.password)
@ -45,7 +45,7 @@ export function useLogin() {
catch (err) {
console.log(err);
updateState({ busy: false })
throw 'login failed: check your username and password';
throw new Error('login failed: check your username and password');
}
updateState({ busy: false })
}
@ -92,7 +92,7 @@ export function useLogin() {
count();
}
}
}, [app])
}, [app, navigate, search])
return { state, actions };
}

View File

@ -1,4 +1,3 @@
import React, { useContext, useEffect } from 'react';
export function Admin() {
return <></>

View File

@ -16,7 +16,7 @@ export function Root() {
navigate('/login');
}
}
}, [app]);
}, [app, navigate]);
return <></>
}

View File

@ -1,4 +1,3 @@
import React, { useContext, useEffect } from 'react';
export function Session() {
return <></>