diff --git a/package.json b/package.json
index 36e9725..4829784 100644
--- a/package.json
+++ b/package.json
@@ -12,12 +12,12 @@
"web-vitals": "^2.1.4"
},
"devDependencies": {
- "eslint": "^8.27.0",
- "eslint-plugin-react": "^7.31.10",
- "http-proxy-middleware": "^2.0.6",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
- "@testing-library/user-event": "^13.5.0"
+ "@testing-library/user-event": "^13.5.0",
+ "eslint": "^8.27.0",
+ "eslint-plugin-react": "^7.31.10",
+ "http-proxy-middleware": "^2.0.6"
},
"scripts": {
"start": "react-scripts start",
diff --git a/src/App.js b/src/App.js
index bf0a04e..9a94681 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
-import { BrowserRouter, Navigate, Route, Routes} from 'react-router-dom';
+import { Navigate, Route, Routes, useNavigate} from 'react-router-dom';
import './css/App.css';
import Home from './pages/Home';
@@ -8,7 +8,7 @@ import Sidebar, { SidebarMenu } from './components/Sidebar';
import UserControls from './components/UserControls';
import { useLoginContext } from './structures/UserContext';
import Login from './pages/Login';
-import { fetchUser } from './util/Util';
+import { get, setSession, setSettings } from './util/Util';
import PrivateRoute from './structures/PrivateRoute';
import { UnauthedRoute } from './structures/UnauthedRoute';
import Users from './pages/Users';
@@ -20,12 +20,21 @@ function App() {
const [user, updateUser] = useLoginContext();
const [loading, setLoading] = useState(true);
+ const navigate = useNavigate();
useEffect(() => {
(async () => {
- await fetchUser();
- updateUser();
+
+ const settings = await get('/api/settings');
+ setSettings(settings.data);
+
+ const result = await get('/api/user');
+ if (result.status === 200) {
+ setSession(result.data);
+ updateUser();
+ }
setLoading(false);
+ if (result.data?.twoFactor) return navigate('/login/verify');
})();
}, []);
@@ -42,8 +51,6 @@ function App() {
-
-
{user ?
@@ -93,7 +100,6 @@ function App() {
-
diff --git a/src/components/Sidebar.js b/src/components/Sidebar.js
index a1c31dc..98d5e0f 100644
--- a/src/components/Sidebar.js
+++ b/src/components/Sidebar.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {} from 'react';
import '../css/components/Sidebar.css';
import NavLink from '../structures/NavLink';
import logoImg from '../img/logo.png';
@@ -14,7 +14,7 @@ const Sidebar = ({children}) => {
};
-const expandMenu = (event) => {
+const toggleMenu = (event) => {
event.preventDefault();
event.target.parentElement.classList.toggle("open");
};
@@ -54,9 +54,10 @@ const SidebarMenu = ({menuItems = [], children}) => {
if(relative) to = `${menuItem.to}${to}`;
return {label};
});
+
elements.push(
-
- {label}{subElements && }
+
+ {label}{subElements && }
{subElements &&
{subElements}
diff --git a/src/css/components/Sidebar.css b/src/css/components/Sidebar.css
index 27976be..d5c9f03 100644
--- a/src/css/components/Sidebar.css
+++ b/src/css/components/Sidebar.css
@@ -5,6 +5,7 @@
padding: 1rem 0;
z-index: 1000;
border-radius: 0;
+ line-height: 1.95;
}
.sidebar-menu {
diff --git a/src/css/index.css b/src/css/index.css
index 765e0c4..6643dcf 100644
--- a/src/css/index.css
+++ b/src/css/index.css
@@ -82,10 +82,6 @@ h1, h2, h3, h4, h5, h6 {
margin: 0.35em 0 0.35em;
}
-body{
- line-height: 1.95;
-}
-
.pageTitle{
margin: 4px;
}
diff --git a/src/index.js b/src/index.js
index 1068bdb..a39e5ab 100644
--- a/src/index.js
+++ b/src/index.js
@@ -4,11 +4,14 @@ import './css/index.css';
import App from './App';
// import reportWebVitals from './reportWebVitals';
import { UserContext } from './structures/UserContext';
+import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
-
+
+
+
);
// root.render(
diff --git a/src/pages/Home.js b/src/pages/Home.js
index c1376be..3bd67d9 100644
--- a/src/pages/Home.js
+++ b/src/pages/Home.js
@@ -2,12 +2,13 @@ import React, { useRef, useState } from "react";
import { Route, Routes } from "react-router";
import '../css/pages/Home.css';
import { useLoginContext } from "../structures/UserContext";
-import { get, post } from "../util/Util";
+import ErrorBoundary from "../util/ErrorBoundary";
+import { capitalise, get, post } from "../util/Util";
-const Profile = () => {
-
- const [user] = useLoginContext();
+const TwoFactorControls = ({ user }) => {
+
const [twoFactorError, set2FAError] = useState(null);
+ const [displayInput, setDisplayInput] = useState(false);
const [qr, setQr] = useState(null);
const displayQr = async () => {
@@ -16,36 +17,89 @@ const Profile = () => {
setQr(response.message);
};
- const authCodeRef = useRef();
- const disable2FA = async () => {
- const code = authCodeRef.current.value;
- const response = await post('/api/user/2fa/disable', {code});
- if(response.status !== 200) return set2FAError(response.message);
+ const codeRef = useRef();
+ const disable2FA = async (event) => {
+ event.preventDefault();
+ const code = codeRef.current.value;
+ if (!code) return;
+ const response = await post('/api/user/2fa/disable', { code });
+ if (response.status !== 200) return set2FAError(response.message);
};
- const codeRef = useRef();
- const submitCode = async () => {
-
+ const submitCode = async (event) => {
+ event.preventDefault();
const code = codeRef.current.value;
if (!code) return;
const response = await post('/api/user/2fa/verify', { code });
if (response.status !== 200) return set2FAError(response.message);
-
};
+ let inner =
+ {qr ?
+
+
+
+
:
+
}
+
;
+
+
+ if (user.twoFactor) inner =
+ {displayInput ?
+
+ : }
+
;
+
+ return
+ {twoFactorError &&
{twoFactorError}
}
+ {inner}
+
;
+
+};
+
+const ExternalProfile = ({ profile }) => {
+ return
+
{capitalise(profile.provider)}
+
Username: {profile.username}
+
ID: {profile.id}
+
;
+};
+
+const ThirdPartyConnections = ({user}) => {
+
+ const {externalProfiles} = user;
+
+ return
+ {externalProfiles.map(profile => )}
+
;
+
+};
+
+const Profile = () => {
+
+ const [user] = useLoginContext();
+
return
-
Profile
Profile Picture
+
3rd party connections
+
+
@@ -67,25 +121,9 @@ const Profile = () => {
-
-
Two Factor
- {twoFactorError &&
{twoFactorError}
}
- {!user.twoFactor ?
-
- {qr ?
-
-
-
-
:
-
}
-
:
-
-
-
- }
+
+
Two Factor: {user.twoFactor ? 'enabled' : 'disabled'}
+
;
@@ -100,9 +138,11 @@ const Main = () => {
const Home = () => {
- return
- } />
- } />
- ;
+ return
+
+ } />
+ } />
+
+ ;
};
export default Home;
\ No newline at end of file
diff --git a/src/pages/Login.js b/src/pages/Login.js
index 695598f..d7abdd3 100644
--- a/src/pages/Login.js
+++ b/src/pages/Login.js
@@ -4,15 +4,7 @@ import '../css/pages/Login.css';
import logoImg from '../img/logo.png';
import { useLoginContext } from "../structures/UserContext";
import LoadingBar from 'react-top-loading-bar';
-import { fetchUser, post } from "../util/Util";
-
-const loginMethods = [
-{
- name: 'Discord',
- img: 'https://assets-global.website-files.com/6257adef93867e50d84d30e2/636e0a69f118df70ad7828d4_icon_clyde_blurple_RGB.svg'
-}
-];
-
+import { fetchUser, getSettings, post } from "../util/Util";
const CredentialFields = () => {
@@ -21,6 +13,8 @@ const CredentialFields = () => {
const navigate = useNavigate();
const ref = useRef(null);
+ const loginMethods = getSettings()?.OAuthProviders || [];
+
const loginClick = async (event) => {
ref.current.continuousStart();
event.preventDefault();
@@ -71,15 +65,18 @@ const CredentialFields = () => {
Alternate login methods
- {loginMethods.map(method =>
{ window.location.pathname = `/api/login/${method.name}`; }}
- />)}
+ onClick={() => { window.location.pathname = `/api/login/${method.name}`; }}>
+
+
{method.name}
+
)}
;
@@ -92,7 +89,8 @@ const TwoFactor = () => {
const navigate = useNavigate();
const ref = useRef(null);
- const twoFactorClick = async () => {
+ const twoFactorClick = async (event) => {
+ event.preventDefault();
const code = document.getElementById('2faCode').value;
if (!code) return;
ref.current.continuousStart();
@@ -115,8 +113,10 @@ const TwoFactor = () => {
Verification Code
{fail ?
Invalid code
: null}
-
-
+
;
};
diff --git a/src/util/Util.js b/src/util/Util.js
index 4c2ddb9..5f86e16 100644
--- a/src/util/Util.js
+++ b/src/util/Util.js
@@ -4,10 +4,6 @@ export const getUser = () => {
return null;
};
-export const getToken = () => {
- return getUser()?.token || null;
-};
-
export const clearSession = () => {
sessionStorage.removeItem('user');
};
@@ -25,6 +21,16 @@ export const fetchUser = async (force = false) => {
setSession(result.data);
return result.data;
}
+ return result;
+};
+
+export const setSettings = (settings) => {
+ if(settings) sessionStorage.setItem('settings', JSON.stringify(settings));
+};
+
+export const getSettings = () => {
+ const data = sessionStorage.getItem('settings');
+ if (data) return JSON.parse(data);
return null;
};
@@ -66,4 +72,9 @@ export const get = async (url, params) => {
.join('&');
const response = await fetch(url);
return parseResponse(response);
+};
+
+export const capitalise = (str) => {
+ const first = str[0].toUpperCase();
+ return `${first}${str.substring(1)}`;
};
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index a998e3b..50b01da 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7498,7 +7498,7 @@ react-scripts@5.0.1:
react-top-loading-bar@^2.3.1:
version "2.3.1"
- resolved "https://registry.yarnpkg.com/react-top-loading-bar/-/react-top-loading-bar-2.3.1.tgz#d727eb6aaa412eae52a990e5de9f33e9136ac714"
+ resolved "https://registry.corgi.wtf/react-top-loading-bar/-/react-top-loading-bar-2.3.1.tgz#d727eb6aaa412eae52a990e5de9f33e9136ac714"
integrity sha512-rQk2Nm+TOBrM1C4E3e6KwT65iXyRSgBHjCkr2FNja1S51WaPulRA5nKj/xazuQ3x89wDDdGsrqkqy0RBIfd0xg==
react@^18.2.0: