From d3838100e0cc45bcc81eb36d15bafd339621d487 Mon Sep 17 00:00:00 2001 From: Wind-Explorer Date: Wed, 26 Jun 2024 15:00:48 +0800 Subject: [PATCH] Enhanced archived account signin experience --- client/src/components/SignInModule.tsx | 21 ++- client/src/components/SignUpModule.tsx | 4 +- client/src/components/UpdateAccountModule.tsx | 14 +- client/src/pages/SpringboardPage.tsx | 142 +++++++++++------- client/src/security/users.ts | 40 ++--- server/routes/users.js | 2 +- 6 files changed, 130 insertions(+), 93 deletions(-) diff --git a/client/src/components/SignInModule.tsx b/client/src/components/SignInModule.tsx index a190c40..9afb306 100644 --- a/client/src/components/SignInModule.tsx +++ b/client/src/components/SignInModule.tsx @@ -1,7 +1,7 @@ import { Button, Link } from "@nextui-org/react"; import { Formik, Form } from "formik"; import * as Yup from "yup"; -import axios from "axios"; +import axios, { AxiosError } from "axios"; import config from "../config"; import NextUIFormikInput from "./NextUIFormikInput"; import { useNavigate } from "react-router-dom"; @@ -33,16 +33,15 @@ export default function SignInModule() { password: "", }; - const handleSubmit = async (values: any) => { - try { - const response = await axios.post( - config.serverAddress + "/users/login", - values - ); - navigate("/springboard/" + response.data.accessToken); - } catch (error) { - console.error("Error logging in:", error); - } + const handleSubmit = (values: any) => { + axios + .post(config.serverAddress + "/users/login", values) + .then((response) => { + navigate("/springboard/" + response.data.accessToken); + }) + .catch((error) => { + throw ((error as AxiosError).response?.data as any).message; + }); }; return ( diff --git a/client/src/components/SignUpModule.tsx b/client/src/components/SignUpModule.tsx index 2f7b283..7456e9f 100644 --- a/client/src/components/SignUpModule.tsx +++ b/client/src/components/SignUpModule.tsx @@ -1,7 +1,7 @@ import { Button, Checkbox, Link } from "@nextui-org/react"; import { Formik, Form, Field, ErrorMessage } from "formik"; import * as Yup from "yup"; -import axios from "axios"; +import axios, { AxiosError } from "axios"; import config from "../config"; import NextUIFormikInput from "./NextUIFormikInput"; import { useNavigate } from "react-router-dom"; @@ -64,7 +64,7 @@ export default function SignUpModule() { ); console.log("User created successfully:", response.data); } catch (error) { - console.error("Error creating user:", error); + throw ((error as AxiosError).response?.data as any).message; } }; diff --git a/client/src/components/UpdateAccountModule.tsx b/client/src/components/UpdateAccountModule.tsx index 13d16be..bfb937d 100644 --- a/client/src/components/UpdateAccountModule.tsx +++ b/client/src/components/UpdateAccountModule.tsx @@ -1,4 +1,4 @@ -import axios from "axios"; +import axios, { AxiosError } from "axios"; import * as Yup from "yup"; import config from "../config"; import { useEffect, useState } from "react"; @@ -18,7 +18,13 @@ export default function UpdateAccountModule({ let [userInformation, setUserInformation] = useState(); useEffect(() => { - retrieveUserInformation(accessToken!, setUserInformation); + retrieveUserInformation(accessToken!) + .then((response) => { + setUserInformation(response); + }) + .catch(() => { + navigate("/springboard/" + accessToken); + }); }, [accessToken]); const validationSchema = Yup.object({ @@ -63,7 +69,7 @@ export default function UpdateAccountModule({ console.log("User updated successfully:", response.data); navigate("/springboard/" + accessToken); } catch (error) { - console.error("Error updating user:", error); + throw ((error as AxiosError).response?.data as any).message; } }; @@ -95,7 +101,7 @@ export default function UpdateAccountModule({ } ) .then(() => { - navigate("/login"); + navigate("/signin"); }) .catch((err) => { console.log("Archive failed: " + err); diff --git a/client/src/pages/SpringboardPage.tsx b/client/src/pages/SpringboardPage.tsx index 3dce4f2..8df4f2d 100644 --- a/client/src/pages/SpringboardPage.tsx +++ b/client/src/pages/SpringboardPage.tsx @@ -10,6 +10,7 @@ import { retrieveUserInformation } from "../security/users"; export default function SpringboardPage() { let { accessToken } = useParams(); // TODO: Replace AT from props with AT from localstorage let [userInformation, setUserInformation] = useState(); + let [accountUnavailable, setAccountUnavaliable] = useState(false); let timeOfDay = getTimeOfDay(); const navigate = useNavigate(); @@ -23,63 +24,102 @@ export default function SpringboardPage() { greeting = "Good evening"; } - useEffect( - () => retrieveUserInformation(accessToken!, setUserInformation), - [] - ); + useEffect(() => { + retrieveUserInformation(accessToken!) + .then((response) => { + setUserInformation(response); + }) + .catch((error) => { + setAccountUnavaliable(true); + }); + return; + }, []); return ( - {userInformation && ( -
-
-
-

- {greeting}, {userInformation.firstName}. -

-

- Resident of Bishan-Toa Payoh Town Council -

-
- } - onPress={() => { - navigate("/manage-account/" + accessToken); - }} - > - Manage your account - +
+ {userInformation && ( +
+
+
+

+ {greeting}, {userInformation.firstName}. +

+

+ Resident of Bishan-Toa Payoh Town Council +

+
+ } + onPress={() => { + navigate("/manage-account/" + accessToken); + }} + > + Manage your account + +
+
-
+
+ + + + +
+
-
- - - - + )} +
+
+ {accountUnavailable && ( +
+
+

🔒

+
+

Account unavailable.

+
+

+ This account seems to have been archived. +

+

+ In order to recover the account, please{" "} + + contact us + +

+
+
+
+
+
+
+ +
+
-
-
- )} + )} +
); } diff --git a/client/src/security/users.ts b/client/src/security/users.ts index 5e35f62..d1c586f 100644 --- a/client/src/security/users.ts +++ b/client/src/security/users.ts @@ -1,31 +1,23 @@ -import axios from "axios"; +import axios, { AxiosError } from "axios"; import config from "../config"; -export function retrieveUserInformation( - accessToken: string, - andThen: React.Dispatch -) { - axios - .get(`${config.serverAddress}/users/auth`, { +export async function retrieveUserInformation(accessToken: string) { + try { + let userId = await axios.get(`${config.serverAddress}/users/auth`, { headers: { Authorization: `Bearer ${accessToken}`, }, - }) - .then((response) => { - axios - .get(`${config.serverAddress}/users/individual/${response.data.id}`, { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - }) - .then((response) => { - andThen(response.data); - }) - .catch((error) => { - console.error("Error retrieving user information:", error); - }); - }) - .catch((error) => { - console.error("Error retrieving user ID:", error); }); + let userInformation = await axios.get( + `${config.serverAddress}/users/individual/${userId.data.id}`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + } + ); + return userInformation.data; + } catch (error) { + throw ((error as AxiosError).response?.data as any).message; + } } diff --git a/server/routes/users.js b/server/routes/users.js index 43c41a7..ee868b3 100644 --- a/server/routes/users.js +++ b/server/routes/users.js @@ -96,7 +96,7 @@ router.get("/individual/:id", validateToken, async (req, res) => { if (user.isArchived) { res.status(400).json({ - message: `Account ${id} is archived.`, + message: `ERR_ACC_IS_ARCHIVED`, }); } else { res.json(user);