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 { 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 (

View File

@@ -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;
}
};

View File

@@ -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<any>();
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);

View File

@@ -10,6 +10,7 @@ import { retrieveUserInformation } from "../security/users";
export default function SpringboardPage() {
let { accessToken } = useParams<string>(); // TODO: Replace AT from props with AT from localstorage
let [userInformation, setUserInformation] = useState<any>();
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 (
<DefaultLayout>
{userInformation && (
<div className="flex flex-col w-full">
<div className="flex flex-row justify-between p-8 *:my-auto">
<div className="flex flex-col gap-4">
<p className="text-3xl font-bold">
{greeting}, {userInformation.firstName}.
</p>
<p>
Resident of <Link>Bishan-Toa Payoh Town Council</Link>
</p>
<Button
className="w-max"
size="sm"
variant="flat"
color="primary"
startContent={
<div className="scale-80">
<PencilSquareIcon />
</div>
}
onPress={() => {
navigate("/manage-account/" + accessToken);
}}
>
Manage your account
</Button>
<div>
{userInformation && (
<div className="flex flex-col w-full">
<div className="flex flex-row justify-between p-8 *:my-auto">
<div className="flex flex-col gap-4">
<p className="text-3xl font-bold">
{greeting}, {userInformation.firstName}.
</p>
<p>
Resident of <Link>Bishan-Toa Payoh Town Council</Link>
</p>
<Button
className="w-max"
size="sm"
variant="flat"
color="primary"
startContent={
<div className="scale-80">
<PencilSquareIcon />
</div>
}
onPress={() => {
navigate("/manage-account/" + accessToken);
}}
>
Manage your account
</Button>
</div>
<div className="bg-red-500 w-40 h-40 rounded-full"></div>
</div>
<div className="bg-red-500 w-40 h-40 rounded-full"></div>
<div className="flex flex-row justify-stretch *:w-full *:h-56 w-full p-4 pt-0 gap-4">
<SpringboardButton
title="Community Forums"
subtitle="Be involved in discussions among your neighbourhood"
></SpringboardButton>
<SpringboardButton
title="Events"
subtitle="Participate in exciting upcoming events around Singapore"
></SpringboardButton>
<SpringboardButton
title="Home Bill Contest"
subtitle="Save resources, win vouchers!"
></SpringboardButton>
<SpringboardButton
title="Karang Guni Scheduling"
subtitle="Arrange doorstep sales for your old gears with Karang Guni"
></SpringboardButton>
</div>
<div className="w-full h-[600px] bg-red-500"></div>
</div>
<div className="flex flex-row justify-stretch *:w-full *:h-56 w-full p-4 pt-0 gap-4">
<SpringboardButton
title="Community Forums"
subtitle="Be involved in discussions among your neighbourhood"
></SpringboardButton>
<SpringboardButton
title="Events"
subtitle="Participate in exciting upcoming events around Singapore"
></SpringboardButton>
<SpringboardButton
title="Home Bill Contest"
subtitle="Save resources, win vouchers!"
></SpringboardButton>
<SpringboardButton
title="Karang Guni Scheduling"
subtitle="Arrange doorstep sales for your old gears with Karang Guni"
></SpringboardButton>
)}
</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 className="w-full h-[600px] bg-red-500"></div>
</div>
)}
)}
</div>
</DefaultLayout>
);
}

View File

@@ -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<any>
) {
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;
}
}

View File

@@ -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);