diff --git a/net/web/src/App.styled.js b/net/web/src/App.styled.js
index a3e351a9..25b48106 100644
--- a/net/web/src/App.styled.js
+++ b/net/web/src/App.styled.js
@@ -1,5 +1,4 @@
import styled from 'styled-components';
-import Colors from 'constants/Colors';
export const AppWrapper = styled.div`
position: absolute;
diff --git a/net/web/src/access/Access.jsx b/net/web/src/access/Access.jsx
index 4ca4ce19..e1b2a825 100644
--- a/net/web/src/access/Access.jsx
+++ b/net/web/src/access/Access.jsx
@@ -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
}
+ if (mode === 'create') {
+ return
+ }
return <>>
}
diff --git a/net/web/src/access/createAccount/CreateAccount.jsx b/net/web/src/access/createAccount/CreateAccount.jsx
new file mode 100644
index 00000000..8ac90e7f
--- /dev/null
+++ b/net/web/src/access/createAccount/CreateAccount.jsx
@@ -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 (
+
+
+
Databag
+
actions.onSettings()}>
+
+
+
+ Create Account
+
+
+ );
+};
+
diff --git a/net/web/src/access/createAccount/CreateAccount.styled.js b/net/web/src/access/createAccount/CreateAccount.styled.js
new file mode 100644
index 00000000..9263de7c
--- /dev/null
+++ b/net/web/src/access/createAccount/CreateAccount.styled.js
@@ -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;
+ }
+`;
+
+
diff --git a/net/web/src/access/createAccount/useCreateAccount.hook.js b/net/web/src/access/createAccount/useCreateAccount.hook.js
new file mode 100644
index 00000000..60a63047
--- /dev/null
+++ b/net/web/src/access/createAccount/useCreateAccount.hook.js
@@ -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 };
+}
+
diff --git a/net/web/src/access/login/Login.jsx b/net/web/src/access/login/Login.jsx
index b003a2f2..bdb1e44c 100644
--- a/net/web/src/access/login/Login.jsx
+++ b/net/web/src/access/login/Login.jsx
@@ -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() {
actions.setUsername(e.target.value)}
- autocapitalize="none" onKeyDown={(e) => keyDown(e)} prefix={} />
+ autocomplete="username" autocapitalize="none" onKeyDown={(e) => keyDown(e)} prefix={} />
actions.setPassword(e.target.value)}
- onKeyDown={(e) => keyDown(e)} prefix={} />
+ autocomplete="current-password" onKeyDown={(e) => keyDown(e)} prefix={} />
diff --git a/net/web/src/access/login/useLogin.hook.js b/net/web/src/access/login/useLogin.hook.js
index 75909e6e..2e4bc752 100644
--- a/net/web/src/access/login/useLogin.hook.js
+++ b/net/web/src/access/login/useLogin.hook.js
@@ -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 };
}
diff --git a/net/web/src/admin/Admin.jsx b/net/web/src/admin/Admin.jsx
index 3f31a7eb..f9cf6a89 100644
--- a/net/web/src/admin/Admin.jsx
+++ b/net/web/src/admin/Admin.jsx
@@ -1,4 +1,3 @@
-import React, { useContext, useEffect } from 'react';
export function Admin() {
return <>>
diff --git a/net/web/src/root/Root.jsx b/net/web/src/root/Root.jsx
index bb71ece2..d07ebbd3 100644
--- a/net/web/src/root/Root.jsx
+++ b/net/web/src/root/Root.jsx
@@ -16,7 +16,7 @@ export function Root() {
navigate('/login');
}
}
- }, [app]);
+ }, [app, navigate]);
return <>>
}
diff --git a/net/web/src/session/Session.jsx b/net/web/src/session/Session.jsx
index 7cf4c689..9451c342 100644
--- a/net/web/src/session/Session.jsx
+++ b/net/web/src/session/Session.jsx
@@ -1,4 +1,3 @@
-import React, { useContext, useEffect } from 'react';
export function Session() {
return <>>