+ const [file, setFile] = useState(null);
+
+ const submit = (event) => {
+ event.preventDefault();
+ console.log(file);
+ };
+
+ return
+
+
+
Thematic customisation
+
+
+
+
+
Dingus
+
+
+
;
};
diff --git a/src/pages/Home.js b/src/pages/Home.js
index 1fe1182..7cda0bf 100644
--- a/src/pages/Home.js
+++ b/src/pages/Home.js
@@ -1,190 +1,14 @@
-import React, { useRef, useState } from "react";
+import React from "react";
import { Route, Routes } from "react-router";
import '../css/pages/Home.css';
-import { useLoginContext } from "../structures/UserContext";
import ErrorBoundary from "../util/ErrorBoundary";
-import { capitalise, get, post } from "../util/Util";
-
-const TwoFactorControls = ({ user }) => {
-
- const [twoFactorError, set2FAError] = useState(null);
- const [displayInput, setDisplayInput] = useState(false);
-
- const [qr, setQr] = useState(null);
- const displayQr = async () => {
- const response = await get('/api/user/2fa');
- if (response.status !== 200) return set2FAError(response.message);
- setQr(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 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();
- const [file, setFile] = useState(null);
- const fileSelector = useRef();
- const [fileName, setFileName] = useState(null);
- const [error, setError] = useState(null);
-
- // For some reason this has to be done for onDrop to work
- const onDragOver = (event) => {
- event.stopPropagation();
- event.preventDefault();
- };
-
- const onDrop = (event) => {
- event.preventDefault();
- const { dataTransfer } = event;
- if (!dataTransfer.files.length) return;
-
- const [file] = dataTransfer.files;
- console.log(file.name);
- setFileName(`Selected: ${file.name}`);
- setFile(file);
- };
-
- const fileGarbage = (event) => {
- setFile(event.target.files[0]);
- setFileName(`Selected: ${event.target.files[0].name}`);
- };
-
- const submit = async ({target: button}) => {
- button.disabled = true;
- if (!file) return;
-
- const body = new FormData();
- body.set('file', file, file.name);
- // body.set('name', file.name);
-
- const response = await post('/api/user/avatar', body, { headers: null });
- if (!response.success) setError(response.message);
- else fileSelector.current.value = null;
- button.disabled = false;
- };
-
- return
-
-
-
Profile
-
-
-
Profile Picture
-
-
-
-
Change Profile Picture
-
-
-
-
Third party connections
-
-
-
-
-
-
Settings
-
-
ID: {user.id}
-
-
-
-
Two Factor: {user.twoFactor ? 'enabled' : 'disabled'}
-
-
-
-
;
-};
+import Applications from "./home/Applications";
+import Profile from "./home/Profile";
const Main = () => {
return
-
+ What to put here? hmmm
;
};
@@ -194,6 +18,7 @@ const Home = () => {
} />
} />
+ } />
;
};
diff --git a/src/pages/Users.js b/src/pages/Users.js
index 29b350b..cd0c8d0 100644
--- a/src/pages/Users.js
+++ b/src/pages/Users.js
@@ -68,7 +68,7 @@ const ApplicationList = ({ apps }) => {
return
{apps.map(app => {
- navigate(`${window.location.pathname}/applications/${app.id}`);
+ navigate(`applications/${app.id}`);
}}
key={app.id}
item={app}
@@ -219,7 +219,7 @@ const Users = () => {
const UserWrapper = () => {
const { id } = useParams();
const user = users.find(u => u.id === id);
- if (!user) return null;
+ if (!user) return Unknown user
;
return ;
};
diff --git a/src/pages/home/Applications.js b/src/pages/home/Applications.js
new file mode 100644
index 0000000..b55ae76
--- /dev/null
+++ b/src/pages/home/Applications.js
@@ -0,0 +1,102 @@
+import React, { useEffect, useRef, useState } from "react";
+import { Route, Routes, useNavigate, useParams } from "react-router";
+import { Table, TableListEntry } from "../../components/Table";
+import ErrorBoundary from "../../util/ErrorBoundary";
+import { post, get, del } from "../../util/Util";
+
+const Application = ({ app }) => {
+
+ const navigate = useNavigate();
+
+ const deleteApp = async () => {
+ const response = await del(`/api/user/applications/${app.id}`);
+ };
+
+ return
+
+
{app.name}
+
{app.description}
+
{app.token}
+
+
;
+
+};
+
+const Applications = () => {
+
+ const [applications, setApplications] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ (async () => {
+ const response = await get('/api/user/applications');
+ if (response.status === 200) setApplications(response.data);
+ setLoading(false);
+ })();
+ }, []);
+
+ const descField = useRef();
+ const nameField = useRef();
+ const [error, setError] = useState(null);
+
+ const createApp = async (event) => {
+ event.preventDefault();
+ const button = event.target;
+
+ const name = nameField.current.value;
+ if(!name) return setError('Missing name');
+ const description = descField.current.value;
+ nameField.current.value = '';
+ descField.current.value = '';
+ button.disabled = true;
+ const response = await post('/api/user/applications', { name, description });
+ if (response.status !== 200) setError(response.message);
+ else setApplications((apps) => [...apps, response.data]);
+
+ button.disabled = false;
+ };
+
+ const Main = () => {
+ return
+
+
+
Applications
+
+ {applications.map(application => navigate(application.id)}
+ item={application}
+ itemKeys={['name', 'id']}
+ />)}
+
+
+
+
+
Create Application
+ {error &&
{error}
}
+
+
+
;
+ };
+
+ const ApplicationWrapper = () => {
+ const { id } = useParams();
+ const application = applications.find(app => app.id === id);
+ if(!application) return Unknown application
;
+ return ;
+ };
+
+ return
+
+ } />
+ } />
+
+ ;
+};
+
+export default Applications;
\ No newline at end of file
diff --git a/src/pages/home/Profile.js b/src/pages/home/Profile.js
new file mode 100644
index 0000000..e7f76a7
--- /dev/null
+++ b/src/pages/home/Profile.js
@@ -0,0 +1,187 @@
+import React, { useRef, useState } from "react";
+import { capitalise, get, post } from "../../util/Util";
+import { useLoginContext } from "../../structures/UserContext";
+import FileSelector from "../../components/FileSelector";
+
+const TwoFactorControls = ({ user }) => {
+
+ const [twoFactorError, set2FAError] = useState(null);
+ const [displayInput, setDisplayInput] = useState(false);
+
+ const [qr, setQr] = useState(null);
+ const displayQr = async () => {
+ const response = await get('/api/user/2fa');
+ if (response.status !== 200) return set2FAError(response.message);
+ setQr(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 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();
+ const [file, setFile] = useState(null);
+ const [error, setError] = useState(null);
+
+ const fileSelector = useRef();
+ const usernameRef = useRef();
+ const displayNameRef = useRef();
+ const currPassRef = useRef();
+ const newPassRef = useRef();
+ const newPassRepeatRef = useRef();
+
+ const submit = async ({ target: button }) => {
+ button.disabled = true;
+ if (!file) return;
+
+ const body = new FormData();
+ body.set('file', file, file.name);
+ // body.set('name', file.name);
+
+ const response = await post('/api/user/avatar', body, { headers: null });
+ if (!response.success) setError(response.message);
+ else fileSelector.current.value = null;
+ button.disabled = false;
+ };
+
+ const updateSettings = async (event) => {
+ event.preventDefault();
+ const button = event.target;
+
+ const username = usernameRef.current.value;
+ const displayName = displayNameRef.current.value;
+ const currentPassword = currPassRef.current.value;
+ const newPassword = newPassRef.current.value;
+ const newPasswordRepeat = newPassRepeatRef.current.value;
+
+ if (!currentPassword) return setError('Missing password');
+
+ button.disabled = true;
+ const data = { username, displayName, password: currentPassword };
+ if (currentPassword && newPassword && newPasswordRepeat) {
+ if (newPassword !== newPasswordRepeat) {
+ button.disabled = false;
+ return setError('Passwords do not match');
+ }
+ data.newPassword = newPassword;
+ }
+ const response = await post('/api/user/settings', data);
+ console.log(response);
+ button.disabled = false;
+
+ };
+
+ return
+
+
+
Profile
+
+
+
Profile Picture
+
+
+
+
Change Profile Picture
+
+
+
+
Third party connections
+
+
+
+
+
+
;
+};
+
+export default Profile;
\ No newline at end of file
diff --git a/src/util/Util.js b/src/util/Util.js
index 8c45c5f..b69c80f 100644
--- a/src/util/Util.js
+++ b/src/util/Util.js
@@ -46,6 +46,7 @@ const parseResponse = async (response) => {
if (status === 401) {
clearSession();
+ if(!location.pathname.includes('/login')) location.pathname = '/login';
}
if (headers['content-type']?.includes('application/json')) {
@@ -83,6 +84,25 @@ export const get = async (url, params) => {
return parseResponse(response);
};
+export const del = async (url, body, opts = {}) => {
+ const options = {
+ method: 'delete',
+ body
+ };
+
+ if (opts.headers !== null) {
+ options.headers = {
+ 'Content-Type': 'application/json',
+ ...opts.headers || {}
+ };
+ }
+
+ if (options.headers && options.headers['Content-Type'] === 'application/json' && body) options.body = JSON.stringify(body);
+
+ const response = await fetch(url, options);
+ return parseResponse(response);
+};
+
export const capitalise = (str) => {
const first = str[0].toUpperCase();
return `${first}${str.substring(1)}`;