Enhanced archived account signin experience

This commit is contained in:
2024-06-26 15:00:48 +08:00
parent 161fa3dd1d
commit d3838100e0
6 changed files with 130 additions and 93 deletions

View File

@@ -1,7 +1,7 @@
import { Button, Link } from "@nextui-org/react"; import { Button, Link } from "@nextui-org/react";
import { Formik, Form } from "formik"; import { Formik, Form } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
import axios from "axios"; import axios, { AxiosError } from "axios";
import config from "../config"; import config from "../config";
import NextUIFormikInput from "./NextUIFormikInput"; import NextUIFormikInput from "./NextUIFormikInput";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@@ -33,16 +33,15 @@ export default function SignInModule() {
password: "", password: "",
}; };
const handleSubmit = async (values: any) => { const handleSubmit = (values: any) => {
try { axios
const response = await axios.post( .post(config.serverAddress + "/users/login", values)
config.serverAddress + "/users/login", .then((response) => {
values
);
navigate("/springboard/" + response.data.accessToken); navigate("/springboard/" + response.data.accessToken);
} catch (error) { })
console.error("Error logging in:", error); .catch((error) => {
} throw ((error as AxiosError).response?.data as any).message;
});
}; };
return ( return (

View File

@@ -1,7 +1,7 @@
import { Button, Checkbox, Link } from "@nextui-org/react"; import { Button, Checkbox, Link } from "@nextui-org/react";
import { Formik, Form, Field, ErrorMessage } from "formik"; import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
import axios from "axios"; import axios, { AxiosError } from "axios";
import config from "../config"; import config from "../config";
import NextUIFormikInput from "./NextUIFormikInput"; import NextUIFormikInput from "./NextUIFormikInput";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@@ -64,7 +64,7 @@ export default function SignUpModule() {
); );
console.log("User created successfully:", response.data); console.log("User created successfully:", response.data);
} catch (error) { } catch (error) {
console.error("Error creating user:", error); throw ((error as AxiosError).response?.data as any).message;
} }
}; };

View File

@@ -1,4 +1,4 @@
import axios from "axios"; import axios, { AxiosError } from "axios";
import * as Yup from "yup"; import * as Yup from "yup";
import config from "../config"; import config from "../config";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
@@ -18,7 +18,13 @@ export default function UpdateAccountModule({
let [userInformation, setUserInformation] = useState<any>(); let [userInformation, setUserInformation] = useState<any>();
useEffect(() => { useEffect(() => {
retrieveUserInformation(accessToken!, setUserInformation); retrieveUserInformation(accessToken!)
.then((response) => {
setUserInformation(response);
})
.catch(() => {
navigate("/springboard/" + accessToken);
});
}, [accessToken]); }, [accessToken]);
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -63,7 +69,7 @@ export default function UpdateAccountModule({
console.log("User updated successfully:", response.data); console.log("User updated successfully:", response.data);
navigate("/springboard/" + accessToken); navigate("/springboard/" + accessToken);
} catch (error) { } 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(() => { .then(() => {
navigate("/login"); navigate("/signin");
}) })
.catch((err) => { .catch((err) => {
console.log("Archive failed: " + err); console.log("Archive failed: " + err);

View File

@@ -10,6 +10,7 @@ import { retrieveUserInformation } from "../security/users";
export default function SpringboardPage() { export default function SpringboardPage() {
let { accessToken } = useParams<string>(); // TODO: Replace AT from props with AT from localstorage let { accessToken } = useParams<string>(); // TODO: Replace AT from props with AT from localstorage
let [userInformation, setUserInformation] = useState<any>(); let [userInformation, setUserInformation] = useState<any>();
let [accountUnavailable, setAccountUnavaliable] = useState(false);
let timeOfDay = getTimeOfDay(); let timeOfDay = getTimeOfDay();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -23,13 +24,20 @@ export default function SpringboardPage() {
greeting = "Good evening"; greeting = "Good evening";
} }
useEffect( useEffect(() => {
() => retrieveUserInformation(accessToken!, setUserInformation), retrieveUserInformation(accessToken!)
[] .then((response) => {
); setUserInformation(response);
})
.catch((error) => {
setAccountUnavaliable(true);
});
return;
}, []);
return ( return (
<DefaultLayout> <DefaultLayout>
<div>
{userInformation && ( {userInformation && (
<div className="flex flex-col w-full"> <div className="flex flex-col w-full">
<div className="flex flex-row justify-between p-8 *:my-auto"> <div className="flex flex-row justify-between p-8 *:my-auto">
@@ -80,6 +88,38 @@ export default function SpringboardPage() {
<div className="w-full h-[600px] bg-red-500"></div> <div className="w-full h-[600px] bg-red-500"></div>
</div> </div>
)} )}
</div>
<div>
{accountUnavailable && (
<div className="flex flex-col">
<div className="flex flex-col gap-8 p-4 justify-center bg-red-500 text-center text-white h-96">
<p className="text-9xl">🔒</p>
<div className="flex flex-col gap-4">
<p className="text-4xl font-bold">Account unavailable.</p>
<div className="flex flex-col">
<p className="text-xl">
This account seems to have been archived.
</p>
<p>
In order to recover the account, please{" "}
<Link className="text-white px-1 rounded-md bg-red-400">
contact us
</Link>
</p>
</div>
<div className="w-min mx-auto"></div>
</div>
</div>
<div className="flex flex-col justify-center p-8">
<div className="w-min mx-auto">
<Button color="primary" onPress={() => navigate("/signin")}>
Sign in with a different account
</Button>
</div>
</div>
</div>
)}
</div>
</DefaultLayout> </DefaultLayout>
); );
} }

View File

@@ -1,31 +1,23 @@
import axios from "axios"; import axios, { AxiosError } from "axios";
import config from "../config"; import config from "../config";
export function retrieveUserInformation( export async function retrieveUserInformation(accessToken: string) {
accessToken: string, try {
andThen: React.Dispatch<any> let userId = await axios.get(`${config.serverAddress}/users/auth`, {
) {
axios
.get(`${config.serverAddress}/users/auth`, {
headers: { headers: {
Authorization: `Bearer ${accessToken}`, Authorization: `Bearer ${accessToken}`,
}, },
}) });
.then((response) => { let userInformation = await axios.get(
axios `${config.serverAddress}/users/individual/${userId.data.id}`,
.get(`${config.serverAddress}/users/individual/${response.data.id}`, { {
headers: { headers: {
Authorization: `Bearer ${accessToken}`, Authorization: `Bearer ${accessToken}`,
}, },
}) }
.then((response) => { );
andThen(response.data); return userInformation.data;
}) } catch (error) {
.catch((error) => { throw ((error as AxiosError).response?.data as any).message;
console.error("Error retrieving user information:", error); }
});
})
.catch((error) => {
console.error("Error retrieving user ID:", error);
});
} }

View File

@@ -96,7 +96,7 @@ router.get("/individual/:id", validateToken, async (req, res) => {
if (user.isArchived) { if (user.isArchived) {
res.status(400).json({ res.status(400).json({
message: `Account ${id} is archived.`, message: `ERR_ACC_IS_ARCHIVED`,
}); });
} else { } else {
res.json(user); res.json(user);