diff --git a/net/web/src/admin/Admin.jsx b/net/web/src/admin/Admin.jsx index d940e001..cbe5baae 100644 --- a/net/web/src/admin/Admin.jsx +++ b/net/web/src/admin/Admin.jsx @@ -1,20 +1,49 @@ -import { UserOutlined } from '@ant-design/icons'; -import { AdminWrapper } from './Admin.styled'; +import React, { useContext, useEffect } from 'react'; +import { useNavigate } from "react-router-dom"; +import { AppContext } from 'context/AppContext'; +import { ViewportContext } from 'context/ViewportContext'; import { useAdmin } from './useAdmin.hook'; +import { AdminWrapper } from './Admin.styled'; +import { Prompt } from './prompt/Prompt'; +import { Dashboard } from './dashboard/Dashboard'; -export function Admin() { +import login from 'images/login.png' + +export function Admin({ mode }) { const { state, actions } = useAdmin(); return ( -
- Databag -
actions.onUser()}> - + { (state.display === 'large' || state.display === 'xlarge') && ( +
+
+ Databag Splash +
+
+ { state.token == null && ( + + )} + { state.token != null && ( + + )} +
-
+ )} + { (state.display === 'medium' || state.display === 'small') && ( +
+
+ { state.token == null && ( + + )} + { state.token != null && ( + + )} +
+
+ )} ); } + diff --git a/net/web/src/admin/Admin.styled.js b/net/web/src/admin/Admin.styled.js index 71613309..3b813167 100644 --- a/net/web/src/admin/Admin.styled.js +++ b/net/web/src/admin/Admin.styled.js @@ -2,30 +2,48 @@ import styled from 'styled-components'; import Colors from 'constants/Colors'; export const AdminWrapper = styled.div` - max-width: 400px; - width: 90%; - height: 90%; - display: flex; - flex-direction: column; + height: 100%; - .app-title { - font-size: 24px; + .full-layout { + width: 100%; + height: 100%; + padding: 8px; + + .center { + width: 100%; + height: 100%; + border-radius: 4px; + background: ${Colors.formBackground}; + display: flex; + align-items: center; + justify-content: center; + } + } + + .split-layout { display: flex; - align-items: flex-start; - justify-content: center; - flex: 1; - color: ${Colors.grey}; + flex-direction: row; + height: 100%; - .user { - color: ${Colors.grey}; - position: absolute; - top: 0px; - right: 0px; - font-size: 20px; - cursor: pointer; - margin: 16px; + .left { + width: 50%; + height: 100%; + padding: 32px; + + .splash { + width: 100%; + height: 100%; + object-fit: contain; + } + } + + .right { + width: 50%; + height: 100%; + background: ${Colors.formBackground}; + display: flex; + align-items: center; + justify-content: center; } } `; - - diff --git a/net/web/src/admin/dashboard/Dashboard.jsx b/net/web/src/admin/dashboard/Dashboard.jsx new file mode 100644 index 00000000..a03eeab3 --- /dev/null +++ b/net/web/src/admin/dashboard/Dashboard.jsx @@ -0,0 +1,91 @@ +import { DashboardWrapper, SettingsButton, AddButton, SettingsLayout, CreateLayout } from './Dashboard.styled'; +import { Tooltip, Button, Modal, Input, InputNumber, Space, List } from 'antd'; +import { SettingOutlined, CopyOutlined, UserAddOutlined, LogoutOutlined, ReloadOutlined } from '@ant-design/icons'; +import { useDashboard } from './useDashboard.hook'; +import { AccountItem } from './accountItem/AccountItem'; + +export function Dashboard({ token, config, logout }) { + + const { state, actions } = useDashboard(token, config); + + const onClipboard = (value) => { + navigator.clipboard.writeText(value); + }; + + const createLink = () => { + return window.location.origin + '/#/create?add=' + state.createToken; + }; + + return ( + + +
+
+
Accounts
+
+ + } + onClick={() => actions.getAccounts()}> + +
+
+ + } + onClick={() => actions.setShowSettings(true)}> + +
+
+ + } + onClick={() => logout()}> + +
+
+ + } + loading={state.createBusy} onClick={() => actions.setCreateLink()}> + +
+
+ +
+ ()} + /> +
+
+ + actions.setSettings()} onCancel={() => actions.setShowSettings(false)}> + +
+
Federated Host: 
+ actions.setHost(e.target.value)} + value={state.host} /> +
+
+
Storage Limit (GB) / Account: 
+ actions.setStorage(e)} + placeholder="0 for unrestricted" value={state.storage} /> +
+
+
+ actions.setShowCreate(false)}>OK ]} + onCancel={() => actions.setShowCreate(false)}> + +
{createLink()}
+ ]} + onCancel={() => actions.setShowAccess(false)}> + +
{accessLink()}
+ +
+ + + + + + ); +}; + diff --git a/net/web/src/admin/prompt/Prompt.styled.js b/net/web/src/admin/prompt/Prompt.styled.js new file mode 100644 index 00000000..d1473c99 --- /dev/null +++ b/net/web/src/admin/prompt/Prompt.styled.js @@ -0,0 +1,58 @@ +import styled from 'styled-components'; +import Colors from 'constants/Colors'; + +export const PromptWrapper = 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}; + + .user { + 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-button { + display: flex; + align-items: center; + justify-content: center; + + .form-login { + width: 50%; + } + } + } + + .form-submit { + background-color: #444444; + } +`; + + diff --git a/net/web/src/admin/prompt/usePrompt.hook.js b/net/web/src/admin/prompt/usePrompt.hook.js new file mode 100644 index 00000000..a860edb9 --- /dev/null +++ b/net/web/src/admin/prompt/usePrompt.hook.js @@ -0,0 +1,75 @@ +import { useContext, useState, useEffect } from 'react'; +import { AppContext } from 'context/AppContext'; +import { useNavigate, useLocation } from "react-router-dom"; +import { getNodeStatus } from 'api/getNodeStatus'; +import { setNodeStatus } from 'api/setNodeStatus'; +import { getNodeConfig } from 'api/getNodeConfig'; + +export function usePrompt() { + + const [state, setState] = useState({ + password: null, + placeholder: '', + unclaimed: null, + busy: false, + }); + + const navigate = useNavigate(); + const app = useContext(AppContext); + + const updateState = (value) => { + setState((s) => ({ ...s, ...value })); + } + + const checkStatus = async () => { + try { + let status = await getNodeStatus(); + updateState({ uncliamed: status }); + } + catch(err) { + console.log("failed to check node status"); + } + }; + + useEffect(() => { + checkStatus(); + }, []); + + const actions = { + setPassword: (password) => { + updateState({ password }); + }, + onUser: () => { + navigate('/login'); + }, + onLogin: async () => { + if (!state.busy) { + try { + updateState({ busy: true }); + if (state.unclaimed === true) { + await setNodeStatus(state.password); + return await getNodeConfig(state.password); + } + else { + return await getNodeConfig(state.password); + } + updateState({ busy: false }); + } + catch (err) { + console.log(err); + updateState({ busy: false }); + throw new Error("access denied"); + } + } + else { + throw new Error("operation in progress"); + } + }, + }; + + useEffect(() => { + }, [app, navigate]) + + return { state, actions }; +} + diff --git a/net/web/src/admin/useAdmin.hook.js b/net/web/src/admin/useAdmin.hook.js index 65939be9..a12b64ce 100644 --- a/net/web/src/admin/useAdmin.hook.js +++ b/net/web/src/admin/useAdmin.hook.js @@ -1,22 +1,28 @@ -import { useContext, useState } from 'react'; -import { AppContext } from 'context/AppContext'; -import { useNavigate } from "react-router-dom"; +import { useContext, useState, useEffect } from 'react'; +import { ViewportContext } from 'context/ViewportContext'; export function useAdmin() { const [state, setState] = useState({ + display: null, }); - const navigate = useNavigate(); - const app = useContext(AppContext); + const viewport = useContext(ViewportContext); const updateState = (value) => { setState((s) => ({ ...s, ...value })); } + useEffect(() => { + updateState({ display: viewport.state.display }); + }, [viewport]); + const actions = { - onUser: () => { - navigate('/login'); + login: (token, config) => { + updateState({ token, config }); + }, + logout: () => { + updateState({ token: null, config: null }); }, };