Revamped routing system

This commit is contained in:
2024-07-26 14:49:40 +08:00
parent 4d1b623ec6
commit 9b293660bf
26 changed files with 666 additions and 601 deletions

View File

@@ -8,7 +8,7 @@ import ManageUserAccountPage from "./pages/ManageUserAccountPage";
import CommunityPage from "./pages/CommunityPage"; import CommunityPage from "./pages/CommunityPage";
import CreatePostPage from "./pages/CreatePostPage"; import CreatePostPage from "./pages/CreatePostPage";
import EditPostPage from "./pages/EditPostPage"; import EditPostPage from "./pages/EditPostPage";
import PostPage from './pages/PostPage'; import PostPage from "./pages/PostPage";
import SchedulePage from "./pages/SchedulePage"; import SchedulePage from "./pages/SchedulePage";
import EventsPage from "./pages/EventsPage"; import EventsPage from "./pages/EventsPage";
import CreateEventsPage from "./pages/CreateEventsPage"; import CreateEventsPage from "./pages/CreateEventsPage";
@@ -17,28 +17,57 @@ import AdministratorSpringboard from "./pages/AdministratorSpringboard";
import HBContestPage from "./pages/HBContestPage"; import HBContestPage from "./pages/HBContestPage";
import HBFormPage from "./pages/HBFormPage"; import HBFormPage from "./pages/HBFormPage";
import EditEventsPage from "./pages/EditEventsPage"; import EditEventsPage from "./pages/EditEventsPage";
import DefaultLayout from "./layouts/default";
import AdministratorLayout from "./layouts/administrator";
function App() { function App() {
return ( return (
<Routes> <Routes>
<Route element={<HomePage />} path="/" /> {/* User Routes */}
<Route element={<SignUpPage />} path="/signup" /> <Route path="/" element={<DefaultLayout />}>
<Route element={<SignInPage />} path="/signin" /> {/* General Routes */}
<Route element={<SpringboardPage />} path="/springboard" /> <Route index element={<HomePage />} />
<Route element={<ManageUserAccountPage />} path="/manage-account" /> <Route element={<SignUpPage />} path="signup" />
<Route element={<AdministratorSpringboard />} path="/admin" /> <Route element={<SignInPage />} path="signin" />
<Route element={<SpringboardPage />} path="springboard" />
<Route element={<ManageUserAccountPage />} path="manage-account" />
<Route element={<CommunityPage />} path="/community" /> {/* Events Route */}
<Route element={<CreatePostPage />} path="/createPost" /> <Route path="events">
<Route element={<EditPostPage />} path="/editPost/:id" /> <Route index element={<EventsPage />} />
<Route element={<PostPage />} path="/post/:id" /> </Route>
<Route element={<SchedulePage />} path="/schedule" />
<Route element={<EventsPage />} path="/events" /> {/* Karang Guni Schedules Route */}
<Route element={<HBContestPage />} path="/contest" /> <Route path="karang-guni-schedules">
<Route element={<HBFormPage />} path="/hbcform" /> <Route index element={<SchedulePage />} />
<Route element={<CreateEventsPage />} path="/createEvent" /> </Route>
<Route element={<ManageEventsPage />} path="/manageEvent" />
<Route element={<EditEventsPage />} path="/editEvent/:id" /> {/* 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" />
</Route>
</Route>
{/* Admin Routes */}
<Route path="/admin" element={<AdministratorLayout />}>
<Route index element={<AdministratorSpringboard />} />
{/* Events */}
<Route path="events">
<Route index element={<ManageEventsPage />} />
<Route element={<CreateEventsPage />} path="create" />
<Route element={<EditEventsPage />} path="edit/:id" />
</Route>
</Route>
</Routes> </Routes>
); );
} }

View File

@@ -26,18 +26,29 @@ import { useEffect, useState } from "react";
import config from "../config"; import config from "../config";
import AdministratorNavigationPanelNavigationButton from "./AdministratorNavigationPanelNavigationButton"; import AdministratorNavigationPanelNavigationButton from "./AdministratorNavigationPanelNavigationButton";
import EcoconnectLogo from "./EcoconnectLogo"; import EcoconnectLogo from "./EcoconnectLogo";
import { useNavigate } from "react-router-dom";
export default function AdministratorNavigationPanel() { export default function AdministratorNavigationPanel() {
const [userInformation, setUserInformation] = useState<any>(); const [userInformation, setUserInformation] = useState<any>();
const [userProfileImageURL, setUserProfileImageURL] = useState(""); const [userProfileImageURL, setUserProfileImageURL] = useState("");
const [panelVisible, setPanelVisible] = useState(true); const [panelVisible, setPanelVisible] = useState(true);
const [isScrolled, setIsScrolled] = useState(false); const [isScrolled, setIsScrolled] = useState(false);
const navigate = useNavigate();
useEffect(() => { useEffect(() => {
retrieveUserInformation().then((value) => { retrieveUserInformation()
.then((value) => {
if (!value || value.accountType != 2) {
navigate("/");
}
setUserInformation(value); setUserInformation(value);
setUserProfileImageURL( setUserProfileImageURL(
`${config.serverAddress}/users/profile-image/${value.id}` `${config.serverAddress}/users/profile-image/${value.id}`
); );
})
.catch(() => {
navigate("/signin");
}); });
const handleScroll = () => { const handleScroll = () => {
setIsScrolled(window.scrollY > 10); setIsScrolled(window.scrollY > 10);

View File

@@ -21,23 +21,23 @@ import { useNavigate } from "react-router-dom";
import EcoconnectFullLogo from "./EcoconnectFullLogo"; import EcoconnectFullLogo from "./EcoconnectFullLogo";
export default function NavigationBar() { export default function NavigationBar() {
let [userProfileImageURL, setUserProfileImageURL] = useState(""); const [userProfileImageURL, setUserProfileImageURL] = useState("");
let [userInformation, setUserInformation] = useState<any>(); const [userInformation, setUserInformation] = useState<any>();
let [doneLoading, setDoneLoading] = useState(false); const [doneLoading, setDoneLoading] = useState(false);
const [isScrolled, setIsScrolled] = useState(false); const [isScrolled, setIsScrolled] = useState(false);
let navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => { useEffect(() => {
retrieveUserInformation() retrieveUserInformation()
.then((value) => { .then((value) => {
if (value.accountType == 2) navigate("/admin");
setUserProfileImageURL( setUserProfileImageURL(
`${config.serverAddress}/users/profile-image/${value.id}` `${config.serverAddress}/users/profile-image/${value.id}`
); );
setUserInformation(value); setUserInformation(value);
}) })
.catch((err) => { .catch(() => {
console.log(err); navigate("/signin");
return;
}) })
.finally(() => { .finally(() => {
setDoneLoading(true); setDoneLoading(true);
@@ -86,7 +86,7 @@ export default function NavigationBar() {
variant="light" variant="light"
size="sm" size="sm"
onPress={() => { onPress={() => {
navigate("/schedule"); navigate("/karang-guni-schedules");
}} }}
> >
<p className="text-lg">Schedules</p> <p className="text-lg">Schedules</p>
@@ -95,7 +95,7 @@ export default function NavigationBar() {
variant="light" variant="light"
size="sm" size="sm"
onPress={() => { onPress={() => {
navigate("/contest"); navigate("/home-bill-contest");
}} }}
> >
<p className="text-lg">HB Contest</p> <p className="text-lg">HB Contest</p>
@@ -104,7 +104,7 @@ export default function NavigationBar() {
variant="light" variant="light"
size="sm" size="sm"
onPress={() => { onPress={() => {
navigate("/community"); navigate("/community-posts");
}} }}
> >
<p className="text-lg">Community Forums</p> <p className="text-lg">Community Forums</p>

View File

@@ -8,6 +8,7 @@ import { useNavigate } from "react-router-dom";
import { ChevronLeftIcon } from "../icons"; import { ChevronLeftIcon } from "../icons";
import { popErrorToast } from "../utilities"; import { popErrorToast } from "../utilities";
import { retrieveUserInformation } from "../security/users"; import { retrieveUserInformation } from "../security/users";
import instance from "../security/http";
const validationSchema = Yup.object({ const validationSchema = Yup.object({
email: Yup.string() email: Yup.string()
@@ -36,7 +37,7 @@ export default function SignInModule() {
}; };
const handleSubmit = (values: any): void => { const handleSubmit = (values: any): void => {
axios instance
.post(config.serverAddress + "/users/login", values) .post(config.serverAddress + "/users/login", values)
.then((response) => { .then((response) => {
localStorage.setItem("accessToken", response.data.accessToken); localStorage.setItem("accessToken", response.data.accessToken);
@@ -44,7 +45,7 @@ export default function SignInModule() {
if (value.accountType == 2) { if (value.accountType == 2) {
navigate("/admin"); navigate("/admin");
} else { } else {
navigate("/springboard/"); navigate("/springboard");
} }
}); });
}) })

View File

@@ -8,8 +8,8 @@ export default function SignedInStatusVerifier({
}: { }: {
children: React.JSX.Element; children: React.JSX.Element;
}) { }) {
let navigate = useNavigate(); const navigate = useNavigate();
let [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
useEffect(() => { useEffect(() => {
retrieveUserInformation() retrieveUserInformation()
.then((value) => { .then((value) => {

View File

@@ -23,7 +23,7 @@ import instance from "../security/http";
export default function UpdateAccountModule() { export default function UpdateAccountModule() {
const navigate = useNavigate(); const navigate = useNavigate();
let [userInformation, setUserInformation] = useState<any>(); const [userInformation, setUserInformation] = useState<any>();
const { isOpen, onOpen, onOpenChange } = useDisclosure(); const { isOpen, onOpen, onOpenChange } = useDisclosure();
@@ -33,7 +33,7 @@ export default function UpdateAccountModule() {
setUserInformation(response); setUserInformation(response);
}) })
.catch(() => { .catch(() => {
navigate("/springboard/"); navigate("/signin");
}); });
}, []); }, []);
@@ -72,7 +72,7 @@ export default function UpdateAccountModule() {
values values
); );
console.log("User updated successfully:", response.data); console.log("User updated successfully:", response.data);
navigate("/springboard/"); navigate("/springboard");
} catch (error) { } catch (error) {
popErrorToast(error); popErrorToast(error);
} }
@@ -127,7 +127,7 @@ export default function UpdateAccountModule() {
<Button <Button
variant="light" variant="light"
onPress={() => { onPress={() => {
navigate("/springboard/"); navigate("/springboard");
}} }}
> >
Cancel Cancel

View File

@@ -1,12 +1,9 @@
import { Toaster } from "react-hot-toast"; import { Toaster } from "react-hot-toast";
import SingaporeAgencyStrip from "../components/SingaporeAgencyStrip"; import SingaporeAgencyStrip from "../components/SingaporeAgencyStrip";
import AdministratorNavigationPanel from "../components/AdministratorNavigationPanel"; import AdministratorNavigationPanel from "../components/AdministratorNavigationPanel";
import { Outlet } from "react-router-dom";
export default function AdministratorLayout({ export default function AdministratorLayout() {
children,
}: {
children: React.ReactNode;
}) {
return ( return (
<div className="relative flex flex-col h-full"> <div className="relative flex flex-col h-full">
<SingaporeAgencyStrip /> <SingaporeAgencyStrip />
@@ -14,7 +11,9 @@ export default function AdministratorLayout({
<div className="h-full z-50"> <div className="h-full z-50">
<AdministratorNavigationPanel /> <AdministratorNavigationPanel />
</div> </div>
<main className="flex-grow">{children}</main> <main className="flex-grow">
<Outlet />
</main>
</div> </div>
<Toaster /> <Toaster />

View File

@@ -1,16 +1,15 @@
import { Toaster } from "react-hot-toast"; import { Toaster } from "react-hot-toast";
import SingaporeAgencyStrip from "../components/SingaporeAgencyStrip"; import SingaporeAgencyStrip from "../components/SingaporeAgencyStrip";
import NavigationBar from "../components/NavigationBar"; import NavigationBar from "../components/NavigationBar";
import { Outlet } from "react-router-dom";
export default function DefaultLayout({ export default function DefaultLayout() {
children,
}: {
children: React.ReactNode;
}) {
return ( return (
<div className="relative flex flex-col h-screen"> <div className="relative flex flex-col h-screen">
<SingaporeAgencyStrip /> <SingaporeAgencyStrip />
<main className="pt-16 flex-grow">{children}</main> <main className="pt-16 flex-grow">
<Outlet />
</main>
<Toaster /> <Toaster />
<NavigationBar /> <NavigationBar />

View File

@@ -1,5 +1,4 @@
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import AdministratorLayout from "../layouts/administrator";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { getTimeOfDay } from "../utilities"; import { getTimeOfDay } from "../utilities";
import { retrieveUserInformation } from "../security/users"; import { retrieveUserInformation } from "../security/users";
@@ -14,7 +13,7 @@ export default function AdministratorSpringboard() {
if (!accessToken) { if (!accessToken) {
navigate("/signin"); navigate("/signin");
} }
let [userInformation, setUserInformation] = useState<any>(); const [userInformation, setUserInformation] = useState<any>();
let timeOfDay = getTimeOfDay(); let timeOfDay = getTimeOfDay();
let greeting = ""; let greeting = "";
@@ -42,7 +41,6 @@ export default function AdministratorSpringboard() {
return ( return (
<div> <div>
{userInformation && ( {userInformation && (
<AdministratorLayout>
<div className="flex flex-col w-full pb-2"> <div className="flex flex-col w-full pb-2">
<div className="flex flex-row justify-between p-8 pt-14 *:my-auto"> <div className="flex flex-row justify-between p-8 pt-14 *:my-auto">
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
@@ -65,16 +63,13 @@ export default function AdministratorSpringboard() {
</div> </div>
} }
onPress={() => { onPress={() => {
navigate("/manage-account/"); navigate("/manage-account");
}} }}
> >
Manage your account Manage your account
</Button> </Button>
</div> </div>
<UserProfilePicture <UserProfilePicture userId={userInformation.id} editable={false} />
userId={userInformation.id}
editable={false}
/>
</div> </div>
<div className="flex flex-row justify-stretch *:w-full *:h-56 w-full p-4 pt-0 gap-4"></div> <div className="flex flex-row justify-stretch *:w-full *:h-56 w-full p-4 pt-0 gap-4"></div>
<Card className="w-full bg-primary-500 p-8 text-white rounded-r-none"> <Card className="w-full bg-primary-500 p-8 text-white rounded-r-none">
@@ -107,7 +102,6 @@ export default function AdministratorSpringboard() {
</div> </div>
</Card> </Card>
</div> </div>
</AdministratorLayout>
)} )}
</div> </div>
); );

View File

@@ -1,5 +1,4 @@
// import { title } from "@/components/primitives"; // import { title } from "@/components/primitives";
import DefaultLayout from "../layouts/default";
import { SetStateAction, useEffect, useState } from "react"; import { SetStateAction, useEffect, useState } from "react";
import { import {
Button, Button,
@@ -117,20 +116,12 @@ export default function CommunityPage() {
} }
}; };
// useEffect(() => {
// retrieveUserInformation()
// .then((response) => {
// setUserInformation(response);
// })
// return;
// }, []);
const handlePostClick = (id: number) => { const handlePostClick = (id: number) => {
navigate(`/post/${id}`); navigate(`post/${id}`);
}; };
return ( return (
<DefaultLayout> <div className="w-full h-full">
<div className="flex flex-row gap-4 m-10"> <div className="flex flex-row gap-4 m-10">
<div className="flex flex-col gap-8 w-full"> <div className="flex flex-col gap-8 w-full">
<div className="flex flex-col"> <div className="flex flex-col">
@@ -163,8 +154,10 @@ export default function CommunityPage() {
<div className="flex flex-row-reverse justify-center items-center"> <div className="flex flex-row-reverse justify-center items-center">
<Dropdown> <Dropdown>
<div> <div>
<DropdownTrigger className="justify-center items-center" <DropdownTrigger
onClick={(e) => e.stopPropagation()}> className="justify-center items-center"
onClick={(e) => e.stopPropagation()}
>
<Button isIconOnly variant="light"> <Button isIconOnly variant="light">
<EllipsisHorizontalIcon /> <EllipsisHorizontalIcon />
</Button> </Button>
@@ -174,7 +167,7 @@ export default function CommunityPage() {
<DropdownItem <DropdownItem
key="edit" key="edit"
onClick={() => { onClick={() => {
navigate(`/editPost/${post.id}`); navigate(`edit/${post.id}`);
}} }}
> >
Edit Edit
@@ -196,12 +189,6 @@ export default function CommunityPage() {
</div> </div>
<div> <div>
<p>Image</p> <p>Image</p>
{/* {userInformation && (
<UserPostImage
userId={userInformation}
editable={true}
/>
)} */}
</div> </div>
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
@@ -210,19 +197,30 @@ export default function CommunityPage() {
<Chip>Tag 2</Chip> <Chip>Tag 2</Chip>
</div> </div>
<div className="flex flex-row"> <div className="flex flex-row">
<Button variant="light" isIconOnly onClick={(e) => e.stopPropagation()}> <Button
variant="light"
isIconOnly
onClick={(e) => e.stopPropagation()}
>
<HandThumbsUpIcon /> <HandThumbsUpIcon />
</Button> </Button>
<Button variant="light" isIconOnly onClick={(e) => e.stopPropagation()}> <Button
variant="light"
isIconOnly
onClick={(e) => e.stopPropagation()}
>
<ChatBubbleOvalLeftEllipsisIcon /> <ChatBubbleOvalLeftEllipsisIcon />
</Button> </Button>
<Button variant="light" isIconOnly onClick={(e) => e.stopPropagation()}> <Button
variant="light"
isIconOnly
onClick={(e) => e.stopPropagation()}
>
<EllipsisHorizontalIcon /> <EllipsisHorizontalIcon />
</Button> </Button>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
); );
})} })}
@@ -234,7 +232,7 @@ export default function CommunityPage() {
className=" bg-primary-500 dark:bg-primary-700 text-white" className=" bg-primary-500 dark:bg-primary-700 text-white"
size="lg" size="lg"
onPress={() => { onPress={() => {
navigate("/createPost"); navigate("create");
}} }}
> >
<p className="font-bold">Create a post!</p> <p className="font-bold">Create a post!</p>
@@ -280,6 +278,6 @@ export default function CommunityPage() {
)} )}
</ModalContent> </ModalContent>
</Modal> </Modal>
</DefaultLayout> </div>
); );
} }

View File

@@ -1,4 +1,3 @@
import DefaultLayout from "../layouts/default";
import { Button } from "@nextui-org/react"; import { Button } from "@nextui-org/react";
import { Formik, Form } from "formik"; import { Formik, Form } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
@@ -32,8 +31,12 @@ const validationSchema = Yup.object({
time: Yup.string().required("Time is required"), time: Yup.string().required("Time is required"),
location: Yup.string().required("Location is required"), location: Yup.string().required("Location is required"),
category: Yup.string().required("Category is required"), category: Yup.string().required("Category is required"),
slotsAvailable: Yup.number().integer().required("Slots Available is required"), slotsAvailable: Yup.number()
imageUrl: Yup.string().url("Invalid URL format").required("Image URL is required") .integer()
.required("Slots Available is required"),
imageUrl: Yup.string()
.url("Invalid URL format")
.required("Image URL is required"),
}); });
const CreateEventsPage = () => { const CreateEventsPage = () => {
@@ -47,7 +50,7 @@ const CreateEventsPage = () => {
location: "", location: "",
category: "", category: "",
slotsAvailable: "", slotsAvailable: "",
imageUrl: "" imageUrl: "",
}; };
const handleSubmit = async ( const handleSubmit = async (
@@ -56,12 +59,15 @@ const CreateEventsPage = () => {
) => { ) => {
console.log("Submitting form with values:", values); // Debug log console.log("Submitting form with values:", values); // Debug log
try { try {
const response = await axios.post(config.serverAddress + "/events", values); const response = await axios.post(
config.serverAddress + "/events",
values
);
console.log("Server response:", response); // Debug log console.log("Server response:", response); // Debug log
if (response.status === 200 || response.status === 201) { if (response.status === 200 || response.status === 201) {
console.log("Event created successfully:", response.data); console.log("Event created successfully:", response.data);
resetForm(); // Clear form after successful submit resetForm(); // Clear form after successful submit
navigate("/manageEvent"); navigate(-1);
} else { } else {
console.error("Error creating event:", response.statusText); console.error("Error creating event:", response.statusText);
} }
@@ -77,7 +83,7 @@ const CreateEventsPage = () => {
}; };
return ( return (
<DefaultLayout> <div className="w-full h-full">
<section className="w-8/12 mx-auto"> <section className="w-8/12 mx-auto">
<Button <Button
variant="light" variant="light"
@@ -163,7 +169,7 @@ const CreateEventsPage = () => {
)} )}
</Formik> </Formik>
</section> </section>
</DefaultLayout> </div>
); );
}; };

View File

@@ -1,4 +1,3 @@
import DefaultLayout from "../layouts/default";
import { Button } from "@nextui-org/react"; import { Button } from "@nextui-org/react";
import { Formik, Form } from "formik"; import { Formik, Form } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
@@ -48,7 +47,7 @@ function CreatePostPage() {
if (response.status === 200) { if (response.status === 200) {
console.log("Post created successfully:", response.data); console.log("Post created successfully:", response.data);
resetForm(); // Clear form after successful submit resetForm(); // Clear form after successful submit
navigate("/community"); navigate(-1);
} else { } else {
console.error("Error creating post:", response.statusText); console.error("Error creating post:", response.statusText);
} }
@@ -64,7 +63,7 @@ function CreatePostPage() {
}; };
return ( return (
<DefaultLayout> <div className="w-full h-full">
<section className="w-8/12 mx-auto"> <section className="w-8/12 mx-auto">
<Button <Button
variant="light" variant="light"
@@ -126,7 +125,7 @@ function CreatePostPage() {
)} )}
</Formik> </Formik>
</section> </section>
</DefaultLayout> </div>
); );
} }

View File

@@ -1,5 +1,4 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from "react";
import DefaultLayout from "../layouts/default";
import { Button } from "@nextui-org/react"; import { Button } from "@nextui-org/react";
import { Formik, Form } from "formik"; import { Formik, Form } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
@@ -33,8 +32,12 @@ const validationSchema = Yup.object({
time: Yup.string().required("Time is required"), time: Yup.string().required("Time is required"),
location: Yup.string().required("Location is required"), location: Yup.string().required("Location is required"),
category: Yup.string().required("Category is required"), category: Yup.string().required("Category is required"),
slotsAvailable: Yup.number().integer().required("Slots Available is required"), slotsAvailable: Yup.number()
imageUrl: Yup.string().url("Invalid URL format").required("Image URL is required") .integer()
.required("Slots Available is required"),
imageUrl: Yup.string()
.url("Invalid URL format")
.required("Image URL is required"),
}); });
const EditEventsPage = () => { const EditEventsPage = () => {
@@ -48,13 +51,15 @@ const EditEventsPage = () => {
location: "", location: "",
category: "", category: "",
slotsAvailable: "", slotsAvailable: "",
imageUrl: "" imageUrl: "",
}); });
useEffect(() => { useEffect(() => {
const fetchEvent = async () => { const fetchEvent = async () => {
try { try {
const response = await axios.get(`${config.serverAddress}/events/${id}`); const response = await axios.get(
`${config.serverAddress}/events/${id}`
);
console.log("Fetched event data:", response.data); // Debug log console.log("Fetched event data:", response.data); // Debug log
setInitialValues(response.data); setInitialValues(response.data);
} catch (error) { } catch (error) {
@@ -71,12 +76,15 @@ const EditEventsPage = () => {
) => { ) => {
console.log("Submitting form with values:", values); // Debug log console.log("Submitting form with values:", values); // Debug log
try { try {
const response = await axios.put(`${config.serverAddress}/events/${id}`, values); const response = await axios.put(
`${config.serverAddress}/events/${id}`,
values
);
console.log("Server response:", response); // Debug log console.log("Server response:", response); // Debug log
if (response.status === 200 || response.status === 201) { if (response.status === 200 || response.status === 201) {
console.log("Event updated successfully:", response.data); console.log("Event updated successfully:", response.data);
resetForm(); // Clear form after successful submit resetForm(); // Clear form after successful submit
navigate("/manageEvent"); navigate(-1);
} else { } else {
console.error("Error updating event:", response.statusText); console.error("Error updating event:", response.statusText);
} }
@@ -92,7 +100,7 @@ const EditEventsPage = () => {
}; };
return ( return (
<DefaultLayout> <div className="w-full h-full">
<section className="w-8/12 mx-auto"> <section className="w-8/12 mx-auto">
<Button <Button
variant="light" variant="light"
@@ -179,7 +187,7 @@ const EditEventsPage = () => {
)} )}
</Formik> </Formik>
</section> </section>
</DefaultLayout> </div>
); );
}; };

View File

@@ -1,4 +1,3 @@
import DefaultLayout from "../layouts/default";
import { Button } from "@nextui-org/react"; import { Button } from "@nextui-org/react";
import { Formik, Form } from "formik"; import { Formik, Form } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
@@ -60,7 +59,7 @@ function editPost() {
if (response.status === 200) { if (response.status === 200) {
console.log("Post updated successfully:", response.data); console.log("Post updated successfully:", response.data);
resetForm(); resetForm();
navigate("/community"); navigate(-1);
} else { } else {
console.error("Error updating post:", response.statusText); console.error("Error updating post:", response.statusText);
} }
@@ -76,7 +75,7 @@ function editPost() {
}; };
return ( return (
<DefaultLayout> <div className="w-full h-full">
<section className="w-8/12 mx-auto"> <section className="w-8/12 mx-auto">
<Button <Button
variant="light" variant="light"
@@ -138,7 +137,7 @@ function editPost() {
</Formik> </Formik>
)} )}
</section> </section>
</DefaultLayout> </div>
); );
} }

View File

@@ -1,9 +1,15 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from "react";
import DefaultLayout from "../layouts/default";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import instance from "../security/http"; import instance from "../security/http";
import config from "../config"; import config from "../config";
import { Card, CardHeader, CardBody, CardFooter, Image, Button } from "@nextui-org/react"; import {
Card,
CardHeader,
CardBody,
CardFooter,
Image,
Button,
} from "@nextui-org/react";
const EventsPage = () => { const EventsPage = () => {
const [events, setEvents] = useState<any[]>([]); const [events, setEvents] = useState<any[]>([]);
@@ -24,7 +30,7 @@ const EventsPage = () => {
}, []); }, []);
return ( return (
<DefaultLayout> <div className="w-full h-full">
<div className="p-8"> <div className="p-8">
<div className="mb-6"> <div className="mb-6">
<h2 className="text-3xl font-semibold text-primary-600">Events</h2> <h2 className="text-3xl font-semibold text-primary-600">Events</h2>
@@ -65,7 +71,7 @@ const EventsPage = () => {
)} )}
</div> </div>
</div> </div>
</DefaultLayout> </div>
); );
}; };

View File

@@ -1,14 +1,18 @@
import { Card, CardHeader, CardBody, CardFooter, Divider, Button } from "@nextui-org/react"; import {
import DefaultLayout from '../layouts/default'; Card,
import { useNavigate } from 'react-router-dom'; CardHeader,
CardBody,
CardFooter,
Divider,
Button,
} from "@nextui-org/react";
import { useNavigate } from "react-router-dom";
export default function HBContestPage() { export default function HBContestPage() {
const navigate = useNavigate();
let navigate = useNavigate();
return ( return (
<DefaultLayout> <div className="w-full h-full">
<section> <section>
<Card className="max-w-[800px] bg-red-50 mx-auto"> <Card className="max-w-[800px] bg-red-50 mx-auto">
<CardHeader className="flex gap-3"> <CardHeader className="flex gap-3">
@@ -18,17 +22,24 @@ export default function HBContestPage() {
</CardHeader> </CardHeader>
<Divider /> <Divider />
<CardBody> <CardBody>
<p>This contest is to encourage residents to reduce the use of electricity and water usage. <p>
This contest would be won by the person with the lowest overall bill average. This contest is to encourage residents to reduce the use of
Join us in this important effort to create a more sustainable future for everyone. electricity and water usage. This contest would be won by the
Participants would be required to input and upload their bills into the form to ensure integrity and honesty. </p> person with the lowest overall bill average. Join us in this
important effort to create a more sustainable future for everyone.
Participants would be required to input and upload their bills
into the form to ensure integrity and honesty.{" "}
</p>
</CardBody> </CardBody>
<Divider /> <Divider />
<CardFooter> <CardFooter>
<div className="flex-col"> <div className="flex-col">
<div> <div>
<h4>Winners</h4> <h4>Winners</h4>
<p>There will 3 winners for each month. Each winner will receive random food vouchers.</p> <p>
There will 3 winners for each month. Each winner will receive
random food vouchers.
</p>
<p>1st: 3 vouchers</p> <p>1st: 3 vouchers</p>
<p>2nd: 2 vouchers</p> <p>2nd: 2 vouchers</p>
<p>3rd: 1 voucher</p> <p>3rd: 1 voucher</p>
@@ -38,7 +49,7 @@ export default function HBContestPage() {
className=" bg-red-500 dark:bg-red-700 text-white" className=" bg-red-500 dark:bg-red-700 text-white"
size="lg" size="lg"
onPress={() => { onPress={() => {
navigate("/hbcform"); navigate("new-submission");
}} }}
> >
<p className="font-bold">Join</p> <p className="font-bold">Join</p>
@@ -48,7 +59,6 @@ export default function HBContestPage() {
</CardFooter> </CardFooter>
</Card> </Card>
</section> </section>
</DefaultLayout> </div>
) );
} }

View File

@@ -1,39 +1,38 @@
import DefaultLayout from '../layouts/default'; import { Button } from "@nextui-org/react";
import { Button } from '@nextui-org/react'; import { ArrowUTurnLeftIcon } from "../icons";
import { ArrowUTurnLeftIcon } from '../icons'; import { useNavigate } from "react-router-dom";
import { useNavigate } from 'react-router-dom'; import { Formik, Form } from "formik";
import { Formik, Form } from 'formik'; import * as Yup from "yup";
import * as Yup from 'yup'; import config from "../config";
import config from '../config'; import NextUIFormikInput from "../components/NextUIFormikInput";
import NextUIFormikInput from '../components/NextUIFormikInput';
import axios from "axios"; import axios from "axios";
import InsertImage from '../components/InsertImage'; import InsertImage from "../components/InsertImage";
const validationSchema = Yup.object({ const validationSchema = Yup.object({
electricalBill: Yup.number() electricalBill: Yup.number()
.typeError('Must be a number') .typeError("Must be a number")
.positive("Must be a positive value") .positive("Must be a positive value")
.max(99999.99, "Value is too large") .max(99999.99, "Value is too large")
.required(), .required(),
waterBill: Yup.number() waterBill: Yup.number()
.typeError('Must be a number') .typeError("Must be a number")
.positive("Must be a positive value") .positive("Must be a positive value")
.max(99999.99, "Value is too large") .max(99999.99, "Value is too large")
.required(), .required(),
totalBill: Yup.number() totalBill: Yup.number()
.typeError('Must be a number') .typeError("Must be a number")
.positive("Must be a positive value") .positive("Must be a positive value")
.max(99999.99, "Value is too large") .max(99999.99, "Value is too large")
.required(), .required(),
noOfDependents: Yup.number() noOfDependents: Yup.number()
.typeError('Must be a number') .typeError("Must be a number")
.integer("Must be a whole number") .integer("Must be a whole number")
.positive("Must be a positive value") .positive("Must be a positive value")
.required(), .required(),
}); });
export default function HBFormPage() { export default function HBFormPage() {
let navigate = useNavigate(); const navigate = useNavigate();
const initialValues: { const initialValues: {
id: string; id: string;
@@ -44,46 +43,49 @@ export default function HBFormPage() {
ebPicture: File | null; ebPicture: File | null;
wbPicture: File | null; wbPicture: File | null;
} = { } = {
id: '', id: "",
electricalBill: '', electricalBill: "",
waterBill: '', waterBill: "",
totalBill: '', totalBill: "",
noOfDependents: '', noOfDependents: "",
ebPicture: null, ebPicture: null,
wbPicture: null, wbPicture: null,
}; };
const handleSubmit = async ( const handleSubmit = async (
values: any, values: any,
{ setSubmitting, resetForm, setFieldError, setFieldValue }: any { setSubmitting, resetForm, setFieldError, setFieldValue }: any
) => { ) => {
const formData = new FormData(); const formData = new FormData();
formData.append('electricalBill', values.electricalBill); formData.append("electricalBill", values.electricalBill);
formData.append('waterBill', values.waterBill); formData.append("waterBill", values.waterBill);
formData.append('totalBill', values.totalBill); formData.append("totalBill", values.totalBill);
formData.append('noOfDependents', values.noOfDependents); formData.append("noOfDependents", values.noOfDependents);
if (values.ebPicture) { if (values.ebPicture) {
formData.append('ebPicture', values.ebPicture); formData.append("ebPicture", values.ebPicture);
} }
if (values.wbPicture) { if (values.wbPicture) {
formData.append('wbPicture', values.wbPicture); formData.append("wbPicture", values.wbPicture);
} }
try { try {
const response = await axios.post(config.serverAddress + "/hbcform", formData, { const response = await axios.post(
config.serverAddress + "/hbcform",
formData,
{
headers: { headers: {
'Content-Type': 'multipart/form-data' "Content-Type": "multipart/form-data",
},
} }
}); );
if (response.status === 200) { if (response.status === 200) {
console.log("Form created successfully:", response.data); console.log("Form created successfully:", response.data);
resetForm(); // Clear form after successful submit resetForm(); // Clear form after successful submit
setFieldValue('ebPicture', null); setFieldValue("ebPicture", null);
setFieldValue('wbPicture', null); setFieldValue("wbPicture", null);
navigate("/contest"); navigate(-1);
} else { } else {
console.error("Error creating form:", response.statusText); console.error("Error creating form:", response.statusText);
} }
@@ -102,12 +104,9 @@ export default function HBFormPage() {
}; };
return ( return (
<DefaultLayout> <div className="w-full h-full">
<section className="w-7/12 mx-auto"> <section className="w-7/12 mx-auto">
<Button <Button variant="light" onPress={() => navigate(-1)}>
variant="light"
onPress={() => navigate(-1)}
>
<ArrowUTurnLeftIcon /> <ArrowUTurnLeftIcon />
</Button> </Button>
</section> </section>
@@ -154,12 +153,12 @@ export default function HBFormPage() {
<div className="flex flex-row gap-8 max-w-xs h-[500px]"> <div className="flex flex-row gap-8 max-w-xs h-[500px]">
<InsertImage <InsertImage
onImageSelected={(file) => { onImageSelected={(file) => {
setFieldValue('ebPicture', file); setFieldValue("ebPicture", file);
}} }}
/> />
<InsertImage <InsertImage
onImageSelected={(file) => { onImageSelected={(file) => {
setFieldValue('wbPicture', file); setFieldValue("wbPicture", file);
}} }}
/> />
</div> </div>
@@ -178,6 +177,6 @@ export default function HBFormPage() {
)} )}
</Formik> </Formik>
</section> </section>
</DefaultLayout> </div>
); );
} }

View File

@@ -1,11 +1,9 @@
import { Button } from "@nextui-org/react"; import { Button } from "@nextui-org/react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import DefaultLayout from "../layouts/default";
export default function HomePage() { export default function HomePage() {
const navigate = useNavigate(); const navigate = useNavigate();
return ( return (
<DefaultLayout> <div className="w-full h-full">
<p>Home</p> <p>Home</p>
<Button <Button
onPress={() => { onPress={() => {
@@ -14,6 +12,6 @@ export default function HomePage() {
> >
Sign up! Sign up!
</Button> </Button>
</DefaultLayout> </div>
); );
} }

View File

@@ -1,6 +1,14 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from "react";
import DefaultLayout from "../layouts/default"; import {
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Avatar, Button } from "@nextui-org/react"; Table,
TableHeader,
TableColumn,
TableBody,
TableRow,
TableCell,
Avatar,
Button,
} from "@nextui-org/react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { PencilSquareIcon, TrashIcon } from "../icons"; import { PencilSquareIcon, TrashIcon } from "../icons";
import axios from "axios"; import axios from "axios";
@@ -38,7 +46,7 @@ const ManageEventsPage = () => {
}; };
return ( return (
<DefaultLayout> <div className="w-full h-full">
<div className="mb-6"> <div className="mb-6">
<h2 className="text-3xl font-semibold text-red-600">Manage Events</h2> <h2 className="text-3xl font-semibold text-red-600">Manage Events</h2>
</div> </div>
@@ -57,7 +65,10 @@ const ManageEventsPage = () => {
<TableRow key={event.id}> <TableRow key={event.id}>
<TableCell> <TableCell>
<div className="flex items-center"> <div className="flex items-center">
<Avatar src={`${config.serverAddress}${event.imageUrl}`} className="mr-4" /> <Avatar
src={`${config.serverAddress}${event.imageUrl}`}
className="mr-4"
/>
{event.title} {event.title}
</div> </div>
</TableCell> </TableCell>
@@ -92,13 +103,12 @@ const ManageEventsPage = () => {
</Table> </Table>
<Button <Button
className="mt-6 bg-red-600 text-white" className="mt-6 bg-red-600 text-white"
onPress={() => navigate("/CreateEvent")} onPress={() => navigate("createEvent")}
> >
Add events Add events
</Button> </Button>
</DefaultLayout> </div>
); );
}; };
export default ManageEventsPage; export default ManageEventsPage;

View File

@@ -1,4 +1,3 @@
import DefaultLayout from "../layouts/default";
import UpdateAccountModule from "../components/UpdateAccountModule"; import UpdateAccountModule from "../components/UpdateAccountModule";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@@ -10,12 +9,12 @@ export default function ManageUserAccountPage() {
} }
return ( return (
<DefaultLayout> <div className="w-full h-full">
<div> <div>
<div className="p-8 flex flex-col gap-8"> <div className="p-8 flex flex-col gap-8">
<UpdateAccountModule /> <UpdateAccountModule />
</div> </div>
</div> </div>
</DefaultLayout> </div>
); );
} }

View File

@@ -1,6 +1,5 @@
import { useParams, useNavigate } from 'react-router-dom'; import { useParams, useNavigate } from "react-router-dom";
import { useEffect, useState } from 'react'; import { useEffect, useState } from "react";
import DefaultLayout from "../layouts/default";
import instance from "../security/http"; import instance from "../security/http";
import config from "../config"; import config from "../config";
import { import {
@@ -18,12 +17,12 @@ import {
ModalFooter, ModalFooter,
useDisclosure, useDisclosure,
Spinner, Spinner,
} from "@nextui-org/react"; } from "@nextui-org/react";
import { import {
ChatBubbleOvalLeftEllipsisIcon, ChatBubbleOvalLeftEllipsisIcon,
EllipsisHorizontalIcon, EllipsisHorizontalIcon,
HandThumbsUpIcon, HandThumbsUpIcon,
ArrowUTurnLeftIcon, ArrowUTurnLeftIcon,
} from "../icons"; } from "../icons";
interface Post { interface Post {
@@ -50,7 +49,11 @@ const PostPage: React.FC = () => {
}, [id]); }, [id]);
if (!post) { if (!post) {
return <div className="flex justify-center min-h-screen"><Spinner label="Loading..." color="danger" /></div>; return (
<div className="flex justify-center min-h-screen">
<Spinner label="Loading..." color="danger" />
</div>
);
} }
const handleDeleteClick = (post: Post) => { const handleDeleteClick = (post: Post) => {
@@ -71,7 +74,7 @@ const PostPage: React.FC = () => {
}; };
return ( return (
<DefaultLayout> <div className="w-full h-full">
<section className="flex"> <section className="flex">
<div className="w-2/12 flex justify-end"> <div className="w-2/12 flex justify-end">
<Button <Button
@@ -88,7 +91,8 @@ const PostPage: React.FC = () => {
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<section <section
className="flex flex-row gap-4 bg-primary-50 dark:bg-primary-950 border border-none rounded-2xl p-4" className="flex flex-row gap-4 bg-primary-50 dark:bg-primary-950 border border-none rounded-2xl p-4"
key={post.id}> key={post.id}
>
<div> <div>
<Avatar <Avatar
src="https://pbs.twimg.com/media/GOva9x5a0AAK8Bn?format=jpg&name=large" src="https://pbs.twimg.com/media/GOva9x5a0AAK8Bn?format=jpg&name=large"
@@ -113,8 +117,9 @@ const PostPage: React.FC = () => {
<DropdownItem <DropdownItem
key="edit" key="edit"
onClick={() => { onClick={() => {
navigate(`/editPost/${post.id}`); navigate(`edit/${post.id}`);
}}> }}
>
Edit Edit
</DropdownItem> </DropdownItem>
<DropdownItem <DropdownItem
@@ -164,8 +169,7 @@ const PostPage: React.FC = () => {
</div> </div>
</div> </div>
</div> </div>
<div className="w-2/12"> <div className="w-2/12"></div>
</div>
</section> </section>
<Modal isOpen={isOpen} onOpenChange={onOpenChange}> <Modal isOpen={isOpen} onOpenChange={onOpenChange}>
<ModalContent> <ModalContent>
@@ -189,8 +193,8 @@ const PostPage: React.FC = () => {
)} )}
</ModalContent> </ModalContent>
</Modal> </Modal>
</DefaultLayout> </div>
); );
} };
export default PostPage; export default PostPage;

View File

@@ -12,7 +12,6 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@nextui-org/react"; } from "@nextui-org/react";
import DefaultLayout from "../layouts/default";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import config from "../config"; import config from "../config";
import instance from "../security/http"; import instance from "../security/http";
@@ -30,7 +29,7 @@ interface Schedule {
const statusColorMap: Record<string, ChipProps["color"]> = { const statusColorMap: Record<string, ChipProps["color"]> = {
"On going": "success", "On going": "success",
"Up coming": "danger", "Up coming": "danger",
"Ended": "default", Ended: "default",
}; };
const getStatusColor = (status: string): ChipProps["color"] => { const getStatusColor = (status: string): ChipProps["color"] => {
@@ -97,7 +96,7 @@ export default function SchedulePage() {
}; };
return ( return (
<DefaultLayout> <div className="w-full h-full">
<section className="flex flex-col items-center justify-center gap-4 py-8 md:py-10"> <section className="flex flex-col items-center justify-center gap-4 py-8 md:py-10">
<h1>Karang Guni Schedule</h1> <h1>Karang Guni Schedule</h1>
<div className="flex gap-4"> <div className="flex gap-4">
@@ -201,6 +200,6 @@ export default function SchedulePage() {
</div> </div>
</div> </div>
</section> </section>
</DefaultLayout> </div>
); );
} }

View File

@@ -1,11 +1,10 @@
import SignInModule from "../components/SignInModule"; import SignInModule from "../components/SignInModule";
import DefaultLayout from "../layouts/default";
import SignedInStatusVerifier from "../components/SignedInStatusVerifier"; import SignedInStatusVerifier from "../components/SignedInStatusVerifier";
export default function SignInPage() { export default function SignInPage() {
return ( return (
<SignedInStatusVerifier> <SignedInStatusVerifier>
<DefaultLayout> <div className="w-full h-full">
<div className="flex flex-col h-full"> <div className="flex flex-col h-full">
<div className="flex flex-row h-full"> <div className="flex flex-row h-full">
<div className="w-3/5 relative"> <div className="w-3/5 relative">
@@ -33,7 +32,7 @@ export default function SignInPage() {
</div> </div>
</div> </div>
</div> </div>
</DefaultLayout> </div>
</SignedInStatusVerifier> </SignedInStatusVerifier>
); );
} }

View File

@@ -1,11 +1,10 @@
import SignUpModule from "../components/SignUpModule"; import SignUpModule from "../components/SignUpModule";
import DefaultLayout from "../layouts/default";
import SignedInStatusVerifier from "../components/SignedInStatusVerifier"; import SignedInStatusVerifier from "../components/SignedInStatusVerifier";
export default function SignUpPage() { export default function SignUpPage() {
return ( return (
<SignedInStatusVerifier> <SignedInStatusVerifier>
<DefaultLayout> <div className="w-full h-full">
<div className="flex flex-col h-full"> <div className="flex flex-col h-full">
<div className="flex flex-row h-full"> <div className="flex flex-row h-full">
<div className="w-3/5 relative"> <div className="w-3/5 relative">
@@ -33,7 +32,7 @@ export default function SignUpPage() {
</div> </div>
</div> </div>
</div> </div>
</DefaultLayout> </div>
</SignedInStatusVerifier> </SignedInStatusVerifier>
); );
} }

View File

@@ -1,5 +1,4 @@
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import DefaultLayout from "../layouts/default";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Button, Card, Link } from "@nextui-org/react"; import { Button, Card, Link } from "@nextui-org/react";
import { LockClosedIcon, PencilSquareIcon } from "../icons"; import { LockClosedIcon, PencilSquareIcon } from "../icons";
@@ -14,8 +13,8 @@ export default function SpringboardPage() {
if (!accessToken) { if (!accessToken) {
navigate("/signin"); navigate("/signin");
} }
let [userInformation, setUserInformation] = useState<any>(); const [userInformation, setUserInformation] = useState<any>();
let [accountUnavailable, setAccountUnavaliable] = useState(false); const [accountUnavailable, setAccountUnavaliable] = useState(false);
let timeOfDay = getTimeOfDay(); let timeOfDay = getTimeOfDay();
let greeting = ""; let greeting = "";
@@ -42,7 +41,7 @@ export default function SpringboardPage() {
}, []); }, []);
return ( return (
<DefaultLayout> <div className="w-full h-full">
<div> <div>
{userInformation && ( {userInformation && (
<div className="flex flex-col w-full"> <div className="flex flex-col w-full">
@@ -165,6 +164,6 @@ export default function SpringboardPage() {
</div> </div>
)} )}
</div> </div>
</DefaultLayout> </div>
); );
} }

View File

@@ -9,7 +9,7 @@ const instance = axios.create({
instance.interceptors.request.use( instance.interceptors.request.use(
function (config) { function (config) {
// Do something before request is sent // Do something before request is sent
let accessToken = localStorage.getItem("accessToken"); const accessToken = localStorage.getItem("accessToken");
if (accessToken) { if (accessToken) {
config.headers["Authorization"] = `Bearer ${accessToken}`; config.headers["Authorization"] = `Bearer ${accessToken}`;
} }