mirror of
https://github.com/balzack/databag.git
synced 2025-02-14 12:39:17 +00:00
added new create account screen
This commit is contained in:
parent
f10e10d525
commit
78fe7f3cb2
@ -1,5 +1,4 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import Colors from 'constants/Colors';
|
|
||||||
|
|
||||||
export const AppWrapper = styled.div`
|
export const AppWrapper = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -4,6 +4,7 @@ import { AppContext } from 'context/AppContext';
|
|||||||
import { ViewportContext } from 'context/ViewportContext';
|
import { ViewportContext } from 'context/ViewportContext';
|
||||||
import { AccessWrapper } from './Access.styled';
|
import { AccessWrapper } from './Access.styled';
|
||||||
import { Login } from './login/Login';
|
import { Login } from './login/Login';
|
||||||
|
import { CreateAccount } from './createAccount/CreateAccount';
|
||||||
|
|
||||||
import login from 'images/login.png'
|
import login from 'images/login.png'
|
||||||
|
|
||||||
@ -19,12 +20,15 @@ export function Access({ mode }) {
|
|||||||
navigate('/session');
|
navigate('/session');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [app]);
|
}, [app, navigate]);
|
||||||
|
|
||||||
const Prompt = () => {
|
const Prompt = () => {
|
||||||
if (mode === 'login') {
|
if (mode === 'login') {
|
||||||
return <Login />
|
return <Login />
|
||||||
}
|
}
|
||||||
|
if (mode === 'create') {
|
||||||
|
return <CreateAccount />
|
||||||
|
}
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
77
net/web/src/access/createAccount/CreateAccount.jsx
Normal file
77
net/web/src/access/createAccount/CreateAccount.jsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
62
net/web/src/access/createAccount/CreateAccount.styled.js
Normal file
62
net/web/src/access/createAccount/CreateAccount.styled.js
Normal 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;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
111
net/web/src/access/createAccount/useCreateAccount.hook.js
Normal file
111
net/web/src/access/createAccount/useCreateAccount.hook.js
Normal 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 };
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Button, Modal, Form, Input } from 'antd';
|
import { Button, Modal, Form, Input } from 'antd';
|
||||||
import { SettingOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
|
import { SettingOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
|
||||||
import { LoginWrapper, SubmitButton } from './Login.styled';
|
import { LoginWrapper } from './Login.styled';
|
||||||
import { useLogin } from './useLogin.hook';
|
import { useLogin } from './useLogin.hook';
|
||||||
|
|
||||||
export function Login() {
|
export function Login() {
|
||||||
@ -40,12 +39,12 @@ export function Login() {
|
|||||||
|
|
||||||
<Form.Item name="username">
|
<Form.Item name="username">
|
||||||
<Input placeholder="Username" spellCheck="false" onChange={(e) => actions.setUsername(e.target.value)}
|
<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>
|
||||||
|
|
||||||
<Form.Item name="password">
|
<Form.Item name="password">
|
||||||
<Input.Password placeholder="Password" spellCheck="false" onChange={(e) => actions.setPassword(e.target.value)}
|
<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>
|
</Form.Item>
|
||||||
|
|
||||||
<div class="form-button">
|
<div class="form-button">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useContext, useState, useEffect } from 'react';
|
import { useContext, useState, useEffect } from 'react';
|
||||||
import { AppContext } from 'context/AppContext';
|
import { AppContext } from 'context/AppContext';
|
||||||
import { useNavigate, useLocation, useParams } from "react-router-dom";
|
import { useNavigate, useLocation } from "react-router-dom";
|
||||||
|
|
||||||
export function useLogin() {
|
export function useLogin() {
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ export function useLogin() {
|
|||||||
navigate('/admin');
|
navigate('/admin');
|
||||||
},
|
},
|
||||||
onLogin: async () => {
|
onLogin: async () => {
|
||||||
if (!state.busy && state.username != '' && state.password != '') {
|
if (!state.busy && state.username !== '' && state.password !== '') {
|
||||||
updateState({ busy: true })
|
updateState({ busy: true })
|
||||||
try {
|
try {
|
||||||
await app.actions.login(state.username, state.password)
|
await app.actions.login(state.username, state.password)
|
||||||
@ -45,7 +45,7 @@ export function useLogin() {
|
|||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
updateState({ busy: false })
|
updateState({ busy: false })
|
||||||
throw 'login failed: check your username and password';
|
throw new Error('login failed: check your username and password');
|
||||||
}
|
}
|
||||||
updateState({ busy: false })
|
updateState({ busy: false })
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ export function useLogin() {
|
|||||||
count();
|
count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [app])
|
}, [app, navigate, search])
|
||||||
|
|
||||||
return { state, actions };
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import React, { useContext, useEffect } from 'react';
|
|
||||||
|
|
||||||
export function Admin() {
|
export function Admin() {
|
||||||
return <></>
|
return <></>
|
||||||
|
@ -16,7 +16,7 @@ export function Root() {
|
|||||||
navigate('/login');
|
navigate('/login');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [app]);
|
}, [app, navigate]);
|
||||||
|
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import React, { useContext, useEffect } from 'react';
|
|
||||||
|
|
||||||
export function Session() {
|
export function Session() {
|
||||||
return <></>
|
return <></>
|
||||||
|
Loading…
Reference in New Issue
Block a user