diff --git a/net/web/src/access/Access.jsx b/net/web/src/access/Access.jsx index 62aeb372..550375f8 100644 --- a/net/web/src/access/Access.jsx +++ b/net/web/src/access/Access.jsx @@ -4,13 +4,14 @@ import { Login } from './login/Login'; import { Admin } from './admin/Admin'; import { CreateAccount } from './createAccount/CreateAccount'; import { ThemeProvider } from "styled-components"; +import { Select } from 'antd'; -import login from 'images/login.png'; import dogin from 'images/dogin.png'; +import bogin from 'images/bogin.png'; export function Access({ mode }) { - const { state } = useAccess(); + const { state, actions } = useAccess(); return ( @@ -22,7 +23,7 @@ export function Access({ mode }) { Databag Splash )} { state.scheme === 'light' && ( - Databag Splash + Databag Splash )}
@@ -35,6 +36,30 @@ export function Access({ mode }) { { mode === 'admin' && ( )} +
+
+
{state.strings.theme}
+ +
+
)} @@ -50,6 +75,32 @@ export function Access({ mode }) { { mode === 'admin' && ( )} + +
+
+
{state.strings.theme}
+ +
+
+ )} diff --git a/net/web/src/access/Access.styled.js b/net/web/src/access/Access.styled.js index 9191183d..3afbce03 100644 --- a/net/web/src/access/Access.styled.js +++ b/net/web/src/access/Access.styled.js @@ -1,8 +1,22 @@ import styled from 'styled-components'; -import { Colors } from 'constants/Colors'; export const AccessWrapper = styled.div` height: 100%; + color: ${props => props.theme.hintText}; + + .footer { + display: flex; + gap: 32px; + + .option { + gap: 8px; + + .label { + font-size: 12px; + padding: 4px; + } + } + } .full-layout { width: 100%; @@ -13,8 +27,9 @@ export const AccessWrapper = styled.div` width: 100%; height: 100%; border-radius: 4px; - background: ${Colors.formBackground}; + background: ${props => props.theme.frameArea}; display: flex; + flex-direction: column; align-items: center; justify-content: center; } @@ -41,8 +56,9 @@ export const AccessWrapper = styled.div` .right { width: 50%; height: 100%; - background: ${Colors.formBackground}; + background: ${props => props.theme.frameArea}; display: flex; + flex-direction: column; align-items: center; justify-content: center; } diff --git a/net/web/src/access/admin/Admin.jsx b/net/web/src/access/admin/Admin.jsx index 047c0648..9e59c467 100644 --- a/net/web/src/access/admin/Admin.jsx +++ b/net/web/src/access/admin/Admin.jsx @@ -14,9 +14,9 @@ export function Admin() { } catch(err) { modal.error({ - title: 'Login Error', - content: 'Please confirm your password.', - bodyStyle: { padding: 16 }, + title: {state.strings.adminError}, + content: {state.strings.adminMessage}, + bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, }); } } @@ -36,20 +36,20 @@ export function Admin() { -
Admin
+
{state.strings.admin}
- actions.setPassword(e.target.value)} autoComplete="current-password" onKeyDown={(e) => keyDown(e)} prefix={} size="large" />
- +
diff --git a/net/web/src/access/admin/Admin.styled.js b/net/web/src/access/admin/Admin.styled.js index f72b78a6..97a42676 100644 --- a/net/web/src/access/admin/Admin.styled.js +++ b/net/web/src/access/admin/Admin.styled.js @@ -7,6 +7,22 @@ export const AdminWrapper = styled.div` height: 90%; display: flex; flex-direction: column; + + .disabled { + background-color: ${props => props.theme.disabledArea}; + + button { + color: ${props => props.theme.idleText}; + } + } + + .enabled { + background-color: ${props => props.theme.enabledArea}; + + button { + color: ${props => props.theme.activeText}; + } + } .app-title { font-size: 24px; diff --git a/net/web/src/access/admin/useAdmin.hook.js b/net/web/src/access/admin/useAdmin.hook.js index d14cd538..2cde10e0 100644 --- a/net/web/src/access/admin/useAdmin.hook.js +++ b/net/web/src/access/admin/useAdmin.hook.js @@ -4,6 +4,7 @@ import { getNodeStatus } from 'api/getNodeStatus'; import { setNodeStatus } from 'api/setNodeStatus'; import { getNodeConfig } from 'api/getNodeConfig'; import { AppContext } from 'context/AppContext'; +import { SettingsContext } from 'context/SettingsContext'; export function useAdmin() { @@ -12,10 +13,13 @@ export function useAdmin() { placeholder: '', unclaimed: null, busy: false, + strings: {}, + menuStyle: {}, }); const navigate = useNavigate(); const app = useContext(AppContext); + const settings = useContext(SettingsContext); const updateState = (value) => { setState((s) => ({ ...s, ...value })); @@ -61,6 +65,11 @@ export function useAdmin() { }, } + useEffect(() => { + const { strings, menuStyle } = settings.state; + updateState({ strings, menuStyle }); + }, [settings.state]); + return { state, actions }; } diff --git a/net/web/src/access/createAccount/CreateAccount.jsx b/net/web/src/access/createAccount/CreateAccount.jsx index 2f17f911..421ca7a0 100644 --- a/net/web/src/access/createAccount/CreateAccount.jsx +++ b/net/web/src/access/createAccount/CreateAccount.jsx @@ -14,9 +14,9 @@ export function CreateAccount() { } catch(err) { modal.error({ - title: 'Create Account Error', - content: 'Please check with your administrator.', - bodyStyle: { padding: 16 }, + title: {state.strings.createError}, + content: {state.strings.createMessage}, + bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, }); } } @@ -36,32 +36,32 @@ export function CreateAccount() {
-
Create Account
+
{state.strings.createAccount}
- actions.setUsername(e.target.value)} + actions.setUsername(e.target.value)} autoComplete="username" autoCapitalize="none" onKeyDown={(e) => keyDown(e)} prefix={} size="large" />
- actions.setPassword(e.target.value)} + actions.setPassword(e.target.value)} autoComplete="new-password" onKeyDown={(e) => keyDown(e)} prefix={} size="large" /> - actions.setConfirm(e.target.value)} + actions.setConfirm(e.target.value)} autoComplete="new-password" onKeyDown={(e) => keyDown(e)} prefix={} size="large" />
-
@@ -69,7 +69,7 @@ export function CreateAccount() {
diff --git a/net/web/src/access/createAccount/CreateAccount.styled.js b/net/web/src/access/createAccount/CreateAccount.styled.js index 4430b966..6673167e 100644 --- a/net/web/src/access/createAccount/CreateAccount.styled.js +++ b/net/web/src/access/createAccount/CreateAccount.styled.js @@ -8,6 +8,22 @@ export const CreateAccountWrapper = styled.div` display: flex; flex-direction: column; + .disabled { + background-color: ${props => props.theme.disabledArea}; + + button { + color: ${props => props.theme.idleText}; + } + } + + .enabled { + background-color: ${props => props.theme.enabledArea}; + + button { + color: ${props => props.theme.activeText}; + } + } + .app-title { font-size: 24px; display: flex; diff --git a/net/web/src/access/createAccount/useCreateAccount.hook.js b/net/web/src/access/createAccount/useCreateAccount.hook.js index 171c7bab..ddf26cf2 100644 --- a/net/web/src/access/createAccount/useCreateAccount.hook.js +++ b/net/web/src/access/createAccount/useCreateAccount.hook.js @@ -1,5 +1,6 @@ import { useContext, useState, useEffect, useRef } from 'react'; import { AppContext } from 'context/AppContext'; +import { SettingsContext } from 'context/SettingsContext'; import { useNavigate, useLocation } from "react-router-dom"; import { getUsername } from 'api/getUsername'; @@ -13,11 +14,14 @@ export function useCreateAccount() { busy: false, validatetatus: 'success', help: '', + strings: {}, + menuStyle: {}, }); const navigate = useNavigate(); const { search } = useLocation(); const app = useContext(AppContext); + const settings = useContext(SettingsContext); const debounce = useRef(null); const updateState = (value) => { @@ -91,6 +95,11 @@ export function useCreateAccount() { }, }; + useEffect(() => { + const { strings, menuStyle } = settings.state; + updateState({ strings, menuStyle }); + }, [settings.state]); + useEffect(() => { let params = new URLSearchParams(search); let token = params.get("add"); diff --git a/net/web/src/access/login/Login.jsx b/net/web/src/access/login/Login.jsx index 9e5db98c..481dac2d 100644 --- a/net/web/src/access/login/Login.jsx +++ b/net/web/src/access/login/Login.jsx @@ -14,9 +14,9 @@ export function Login() { } catch(err) { modal.error({ - title: 'Login Error', - content: 'Please confirm your username and password.', - bodyStyle: { padding: 16 }, + title: {state.strings.loginError}, + content: {state.strings.loginMessage}, + bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, }); } } @@ -36,32 +36,38 @@ export function Login() {
-
Login
+
+
{ state.strings.login }
+ { !state.available && state.availableSet && ( +
{ state.strings.toCreate }
+ )} +
+
- actions.setUsername(e.target.value)} + actions.setUsername(e.target.value)} autoComplete="username" autoCapitalize="none" onKeyDown={(e) => keyDown(e)} prefix={} size="large" /> - actions.setPassword(e.target.value)} + actions.setPassword(e.target.value)} autoComplete="current-password" onKeyDown={(e) => keyDown(e)} prefix={} size="large" />
-
diff --git a/net/web/src/access/login/Login.styled.js b/net/web/src/access/login/Login.styled.js index d8f474c9..829979d6 100644 --- a/net/web/src/access/login/Login.styled.js +++ b/net/web/src/access/login/Login.styled.js @@ -1,5 +1,4 @@ import styled from 'styled-components'; -import { Colors } from 'constants/Colors'; export const LoginWrapper = styled.div` max-width: 400px; @@ -8,16 +7,32 @@ export const LoginWrapper = styled.div` display: flex; flex-direction: column; + .disabled { + background-color: ${props => props.theme.disabledArea}; + + button { + color: ${props => props.theme.idleText}; + } + } + + .enabled { + background-color: ${props => props.theme.enabledArea}; + + button { + color: ${props => props.theme.activeText}; + } + } + .app-title { font-size: 24px; display: flex; align-items: flex-start; justify-content: center; flex: 1; - color: ${Colors.grey}; + color: ${props => props.theme.hintText}; .settings { - color: ${Colors.grey}; + color: ${props => props.theme.hintText}; position: absolute; top: 0px; right: 0px; @@ -34,6 +49,16 @@ export const LoginWrapper = styled.div` align-items: center; justify-content: center; flex: 1; + flex-direction: column; + } + + .form-message { + font-size: 14px; + padding-top: 8px; + align-items: center; + justify-content: center; + font-weight: normal; + text-align: center; } .form-form { diff --git a/net/web/src/access/login/useLogin.hook.js b/net/web/src/access/login/useLogin.hook.js index f9be90d0..dc27d49c 100644 --- a/net/web/src/access/login/useLogin.hook.js +++ b/net/web/src/access/login/useLogin.hook.js @@ -1,5 +1,6 @@ import { useContext, useState, useEffect } from 'react'; import { AppContext } from 'context/AppContext'; +import { SettingsContext } from 'context/SettingsContext'; import { getAvailable } from 'api/getAvailable'; import { useLocation, useNavigate } from "react-router-dom"; @@ -9,13 +10,17 @@ export function useLogin() { username: '', password: '', available: false, + availableSet: false, disabled: true, busy: false, + strings: {}, + menuStyle: {}, }); const navigate = useNavigate(); const { search } = useLocation(); const app = useContext(AppContext); + const settings = useContext(SettingsContext); const updateState = (value) => { setState((s) => ({ ...s, ...value })); @@ -60,7 +65,7 @@ export function useLogin() { const count = async () => { try { const available = await getAvailable() - updateState({ available: available !== 0 }) + updateState({ availableSet: true, available: available !== 0 }) } catch(err) { console.log(err); @@ -70,6 +75,11 @@ export function useLogin() { // eslint-disable-next-line }, []) + useEffect(() => { + const { strings, menuStyle } = settings.state; + updateState({ strings, menuStyle }); + }, [settings.state]); + const access = async (token) => { if (!state.busy) { updateState({ busy: true }); diff --git a/net/web/src/access/useAccess.hook.js b/net/web/src/access/useAccess.hook.js index 3587194c..a79314f6 100644 --- a/net/web/src/access/useAccess.hook.js +++ b/net/web/src/access/useAccess.hook.js @@ -9,6 +9,11 @@ export function useAccess() { display: null, scheme: null, colors: {}, + theme: null, + themes: [], + language: null, + languages: [], + strings: {}, }); const navigate = useNavigate(); @@ -45,11 +50,18 @@ export function useAccess() { useEffect(() => { - const { colors, display, scheme } = settings.state; - updateState({ colors, display, scheme }); + const { theme, themes, strings, language, languages, colors, display, scheme } = settings.state; + updateState({ theme, themes, language, languages, strings, colors, display, scheme }); }, [settings.state]); - const actions = {}; + const actions = { + setTheme: (theme) => { + settings.actions.setTheme(theme); + }, + setLanguage: (language) => { + settings.actions.setLanguage(language); + }, + }; return { state, actions }; } diff --git a/net/web/src/constants/Colors.js b/net/web/src/constants/Colors.js index e9b03994..78fdc609 100644 --- a/net/web/src/constants/Colors.js +++ b/net/web/src/constants/Colors.js @@ -42,7 +42,7 @@ export const Colors = { export const LightTheme = { splashArea: '#8fbea7', baseArea: '#8fbea7', - frameArea: '#dddddd', + frameArea: '#e4e4e4', iconArea: '#ffffff', headerArea: '#f0f0f0', footerArea: '#f0f0f0', diff --git a/net/web/src/constants/Strings.js b/net/web/src/constants/Strings.js index f1e28d0b..d9682785 100644 --- a/net/web/src/constants/Strings.js +++ b/net/web/src/constants/Strings.js @@ -94,6 +94,19 @@ export const en = { requestConnection: 'Request Connection', cancelRequest: 'Cancel Request', resyncContact: 'Resync Contact', + + login: 'Login', + create: 'Create', + createAccount: 'Create Account', + accountLogin: 'Account Login', + toCreate: 'Accounts are created through a link generated from the admin dashboard.', + admin: 'Admin', + loginError: 'Login Error', + loginMessage: 'Please confirm your username and password.', + createError: 'Create Account Error', + createMessage: 'Please check with your administrator.', + adminError: 'Admin Access Error', + adminMessage: 'Please confirm your password.', }; export const fr = { @@ -192,5 +205,18 @@ export const fr = { requestConnection: 'Demander une Connexion', cancelRequest: 'Annuler la Demande', resyncContact: 'Resynchroniser le Contact', + + login: 'Connecter', + create: 'Créer', + createAccount: 'Créer un Compte', + accountLogin: 'Connexion au Compte', + toCreate: 'Les comptes sont créés via un lien généré depuis le tableau de bord d\'administration.', + admin: 'Administrateur', + loginError: 'Erreur de connexion', + loginMessage: 'Veuillez confirmer votre nom d\'utilisateur et votre mot de passe.', + createError: 'Erreur de création de compte', + createMessage: 'Veuillez vérifier auprès de votre administrateur.', + adminError: 'Erreur d\'Accès', + adminMessage: 'Veuillez confirmer votre mot de passe', }; diff --git a/net/web/src/images/bogin.png b/net/web/src/images/bogin.png new file mode 100644 index 00000000..4cbace0a Binary files /dev/null and b/net/web/src/images/bogin.png differ diff --git a/net/web/src/index.css b/net/web/src/index.css index f0717ef3..889877b4 100644 --- a/net/web/src/index.css +++ b/net/web/src/index.css @@ -24,6 +24,7 @@ body { margin: 0; + background-color: #888888; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; diff --git a/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx b/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx index a0ba6ecb..426f168c 100644 --- a/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx +++ b/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx @@ -77,6 +77,7 @@ export function AccountAccess() {