🔥 Reset password now working

This commit is contained in:
2024-07-29 01:36:44 +08:00
parent 3afe173da7
commit 96efff85da
9 changed files with 506 additions and 186 deletions

View File

@@ -20,42 +20,46 @@ import EditEventsPage from "./pages/EditEventsPage";
import DefaultLayout from "./layouts/default";
import AdministratorLayout from "./layouts/administrator";
import UsersManagement from "./pages/UsersManagement";
import ResetPasswordPage from "./pages/ResetPasswordPage";
function App() {
return (
<Routes>
{/* User Routes */}
<Route path="/" element={<DefaultLayout />}>
{/* General Routes */}
<Route index element={<HomePage />} />
<Route element={<SignUpPage />} path="signup" />
<Route element={<SignInPage />} path="signin" />
<Route element={<SpringboardPage />} path="springboard" />
<Route element={<ManageUserAccountPage />} path="manage-account" />
<Route path="/">
<Route element={<DefaultLayout />}>
{/* General Routes */}
<Route index element={<HomePage />} />
<Route element={<SignUpPage />} path="signup" />
<Route element={<SignInPage />} path="signin" />
<Route element={<SpringboardPage />} path="springboard" />
<Route element={<ManageUserAccountPage />} path="manage-account" />
{/* Events Route */}
<Route path="events">
<Route index element={<EventsPage />} />
</Route>
{/* Events Route */}
<Route path="events">
<Route index element={<EventsPage />} />
</Route>
{/* Karang Guni Schedules Route */}
<Route path="karang-guni-schedules">
<Route index element={<SchedulePage />} />
</Route>
{/* Karang Guni Schedules Route */}
<Route path="karang-guni-schedules">
<Route index element={<SchedulePage />} />
</Route>
{/* Home Bill Contest Route */}
<Route path="home-bill-contest">
<Route index element={<HBContestPage />} />
<Route element={<HBFormPage />} path="new-submission" />
</Route>
{/* Home Bill Contest Route */}
<Route path="home-bill-contest">
<Route index element={<HBContestPage />} />
<Route element={<HBFormPage />} path="new-submission" />
</Route>
{/* Community Posts Route */}
<Route path="community-posts">
<Route index element={<CommunityPage />} />
<Route element={<CreatePostPage />} path="create" />
<Route element={<PostPage />} path="post/:id" />
<Route element={<EditPostPage />} path="edit/:id" />
{/* Community Posts Route */}
<Route path="community-posts">
<Route index element={<CommunityPage />} />
<Route element={<CreatePostPage />} path="create" />
<Route element={<PostPage />} path="post/:id" />
<Route element={<EditPostPage />} path="edit/:id" />
</Route>
</Route>
<Route element={<ResetPasswordPage />} path="reset-password/:token" />
</Route>
{/* Admin Routes */}

View File

@@ -36,9 +36,6 @@ export default function NavigationBar() {
);
setUserInformation(value);
})
.catch(() => {
navigate("/signin");
})
.finally(() => {
setDoneLoading(true);
});

View File

@@ -45,7 +45,7 @@ export default function SignInModule() {
if (value.accountType == 2) {
navigate("/admin");
} else {
navigate("/springboard");
window.location.reload();
}
});
})

View File

@@ -18,7 +18,7 @@ import { Form, Formik } from "formik";
import NextUIFormikInput from "./NextUIFormikInput";
import { useNavigate } from "react-router-dom";
import UserProfilePicture from "./UserProfilePicture";
import { popErrorToast } from "../utilities";
import { popErrorToast, popToast } from "../utilities";
import instance from "../security/http";
export default function UpdateAccountModule() {
@@ -105,6 +105,25 @@ export default function UpdateAccountModule() {
});
};
const sendResetPasswordEmail = () => {
instance
.put(
`${
config.serverAddress
}/users/request-reset-password/${encodeURIComponent(
userInformation.email
)}`
)
.then(() => {
console.log("Email sent successfully");
popToast("Email sent to your mailbox!", 1);
})
.catch((error) => {
console.error("Failed to send email:", error);
popErrorToast("Failed to send email: " + error);
});
};
return (
<div>
{userInformation && (
@@ -221,16 +240,7 @@ export default function UpdateAccountModule() {
color="danger"
variant="light"
onPress={() => {
instance
.put(
`${config.serverAddress}/connections/send-reset-password-email/${userInformation.id}`
)
.then(() => {
console.log("Email sent successfully");
})
.catch((error) => {
console.error("Failed to send email:", error);
});
sendResetPasswordEmail();
}}
>
Reset your password

View File

@@ -0,0 +1,142 @@
import { useParams, useNavigate } from "react-router-dom";
import instance from "../security/http";
import config from "../config";
import { useEffect, useState } from "react";
import { Button, Card, CircularProgress } from "@nextui-org/react";
import EcoconnectFullLogo from "../components/EcoconnectFullLogo";
import NextUIFormikInput from "../components/NextUIFormikInput";
import { Formik, Form } from "formik";
import * as Yup from "yup";
import axios from "axios";
import { popErrorToast, popToast } from "../utilities";
const validationSchema = Yup.object({
password: Yup.string()
.trim()
.max(69, "Password must be at most 69 characters")
.matches(
/^(?=.*[a-zA-Z])(?=.*[0-9]).{1,}$/,
"Password must contain both letters and numbers"
)
.required("Password is required"),
confirmPassword: Yup.string()
.oneOf([Yup.ref("password"), undefined], "Passwords must match")
.required("Confirm Password is required"),
});
export default function ResetPasswordPage() {
const { token } = useParams();
const navigate = useNavigate();
const [validationResult, setValidationResult] = useState<boolean>(false);
const [pageLoading, setPageLoading] = useState<boolean>(true);
const validateToken = () => {
instance
.get(`${config.serverAddress}/users/reset-password/${token}`)
.then(() => {
setValidationResult(true);
})
.catch(() => {
setValidationResult(false);
})
.finally(() => {
setPageLoading(false);
});
};
useEffect(() => {
validateToken();
}, []);
const handleSubmit = (values: any): void => {
console.log("submitting");
instance
.post(`${config.serverAddress}/users/reset-password`, {
token,
password: values.password,
})
.then(() => {
popToast("Success!", 1);
navigate("/signin");
})
.catch((error) => {
popErrorToast(error);
});
};
return (
<div className="absolute inset-0 p-8 w-full h-full flex flex-col justify-center">
<div className="flex flex-row justify-center">
{pageLoading && (
<div>
<CircularProgress label="Loading..." />
</div>
)}
{!pageLoading && (
<div className="flex flex-col gap-8 *:mx-auto">
<Card className="max-w-[600px] w-full mx-auto">
{validationResult && (
<div className="flex flex-col gap-8 p-12 text-left">
<div className="flex flex-col gap-2">
<p className="text-3xl font-bold">Password Reset</p>
<p>Enter a new password below.</p>
</div>
<Formik
initialValues={{ password: "", confirmPassword: "" }}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{({ isValid, dirty }) => (
<Form className="flex flex-col gap-8">
<NextUIFormikInput
label="New Password"
name="password"
type="password"
placeholder="Enter new password"
labelPlacement="outside"
/>
<NextUIFormikInput
label="Confirm Password"
name="confirmPassword"
type="password"
placeholder="Confirm new password"
labelPlacement="outside"
/>
<Button
type="submit"
color="primary"
size="lg"
isDisabled={!isValid || !dirty}
>
Confirm
</Button>
</Form>
)}
</Formik>
</div>
)}
{!validationResult && (
<div className="flex flex-col gap-8 p-12 *:mr-auto text-left">
<div className="flex flex-col gap-2">
<p className="text-3xl font-bold">
Reset portal has been closed.
</p>
<p>Please request for a password reset again.</p>
</div>
</div>
)}
</Card>
<div className="flex flex-row gap-4">
<EcoconnectFullLogo />
<p>·</p>
<p className="opacity-50">
© Copyright {new Date().getFullYear()}. All rights reserved.
</p>
</div>
</div>
)}
</div>
</div>
);
}