From b6e707d0479fbaf51746e190205306dd3e3dbf2e Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Thu, 11 Mar 2021 00:54:57 +1100 Subject: [PATCH] Added account page, read more The account page also has the account deletion button, which was a *real treat* to get working right. --- client/components/app.jsx | 1 + client/components/pages/account.jsx | 103 ++++++++++++++++++++ client/components/panels/delete-account.jsx | 73 ++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 client/components/pages/account.jsx create mode 100644 client/components/panels/delete-account.jsx diff --git a/client/components/app.jsx b/client/components/app.jsx index 0546d56..76308b7 100644 --- a/client/components/app.jsx +++ b/client/components/app.jsx @@ -23,6 +23,7 @@ const App = props => { import('./pages/signup')} /> import('./pages/login')} /> + import('./pages/account')} /> () => } /> () => } /> diff --git a/client/components/pages/account.jsx b/client/components/pages/account.jsx new file mode 100644 index 0000000..a6ff3eb --- /dev/null +++ b/client/components/pages/account.jsx @@ -0,0 +1,103 @@ +import React, { useEffect, useContext, useRef } from 'react'; +import { Redirect } from 'react-router-dom'; + +import { TokenContext } from '../utilities/token-provider'; + +import DeleteAccount from '../panels/delete-account'; + +const Account = props => { + //context + const authTokens = useContext(TokenContext); + + //misplaced? + if (!authTokens.accessToken) { + return ; + } + + //refs + const passwordRef = useRef(); + const retypeRef = useRef(); + const contactRef = useRef(); + + //grab the user's info + useEffect(() => { + authTokens.tokenFetch(`${process.env.AUTH_URI}/account`, { + method: 'GET', + headers: { + 'Access-Control-Allow-Origin': '*' + } + }) + .then(blob => blob.json()) + .then(json => contactRef.current.checked = json.contact) + .catch(e => console.error(e)) + ; + }, []); + + //render the thing + return ( +
+

Account

+
{ + evt.preventDefault(); + const [err, result] = await update(passwordRef.current.value, retypeRef.current.value, contactRef.current.checked, authTokens.tokenFetch); + + if (err) { + alert(err); + return; + } + passwordRef.current.value = retypeRef.current.value = ''; + }}> +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+ + +
+ ); +}; + +const update = async (password, retype, contact, tokenFetch) => { + if (password != retype) { + return ['Passwords do not match']; + } + + if (password && password.length < 8) { + return ['Password is too short']; + } + + const result = await tokenFetch(`${process.env.AUTH_URI}/update`, { + method: 'PATCH', + headers: { + 'Access-Control-Allow-Origin': '*', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + password: password ? password : null, + contact + }) + }); + + if (!result.ok) { + return [`${await result.status}: ${await result.text()}`]; + } else { + return [null]; + } +} + +export default Account; \ No newline at end of file diff --git a/client/components/panels/delete-account.jsx b/client/components/panels/delete-account.jsx new file mode 100644 index 0000000..f56ebfa --- /dev/null +++ b/client/components/panels/delete-account.jsx @@ -0,0 +1,73 @@ +import React, { useState, useContext, useRef } from 'react'; + +import { TokenContext } from '../utilities/token-provider'; + +//DOCS: isolated the delete account button into it's own panel, so it can be easily moved as needed +const DeleteAccount = props => { + const authTokens = useContext(TokenContext); + const [open, setOpen] = useState(false); + const passwordRef = useRef(); + + if (!open) { + return + } + + return ( +
{ + evt.preventDefault(); + const [err] = await handleSubmit(passwordRef.current.value, authTokens); + if (err) { + alert(err); + } + }}> +
+ + +
+ + + +
+ ); +}; + +const handleSubmit = async (password, authTokens) => { + //schedule a deletion + const result = await authTokens.tokenFetch(`${process.env.AUTH_URI}/deletion`, { + method: 'DELETE', + headers: { + 'Access-Control-Allow-Origin': '*', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + password + }) + }); + + if (!result.ok) { + return [`${await result.status}: ${await result.text()}`]; + } + + //force a logout + const result2 = await authTokens.tokenFetch(`${process.env.AUTH_URI}/logout`, { + method: 'DELETE', + headers: { + 'Access-Control-Allow-Origin': '*', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + token: authTokens.refreshToken + }) + }); + + if (!result2.ok) { + return [`${await result2.status}: ${await result2.text()}`]; + } + + authTokens.setAccessToken(''); + authTokens.setRefreshToken(''); + + return [null]; +}; + +export default DeleteAccount; \ No newline at end of file