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,19 +26,30 @@ 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()
setUserInformation(value); .then((value) => {
setUserProfileImageURL( if (!value || value.accountType != 2) {
`${config.serverAddress}/users/profile-image/${value.id}` navigate("/");
); }
}); setUserInformation(value);
setUserProfileImageURL(
`${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,72 +41,67 @@ 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"> <p className="text-3xl font-bold">
<p className="text-3xl font-bold"> {greeting}, {userInformation.firstName}.
{greeting}, {userInformation.firstName}. </p>
</p> <div className="flex flex-row gap-2 *:my-auto">
<div className="flex flex-row gap-2 *:my-auto"> <p className="text-xl">A staff member of</p>
<p className="text-xl">A staff member of</p> <EcoconnectFullLogo />
<EcoconnectFullLogo />
</div>
<p className="text-primary-500">{userInformation.email}</p>
<Button
className="w-max"
size="sm"
variant="flat"
color="primary"
startContent={
<div className="scale-80">
<PencilSquareIcon />
</div>
}
onPress={() => {
navigate("/manage-account/");
}}
>
Manage your account
</Button>
</div> </div>
<UserProfilePicture <p className="text-primary-500">{userInformation.email}</p>
userId={userInformation.id} <Button
editable={false} className="w-max"
/> size="sm"
variant="flat"
color="primary"
startContent={
<div className="scale-80">
<PencilSquareIcon />
</div>
}
onPress={() => {
navigate("/manage-account");
}}
>
Manage your account
</Button>
</div> </div>
<div className="flex flex-row justify-stretch *:w-full *:h-56 w-full p-4 pt-0 gap-4"></div> <UserProfilePicture userId={userInformation.id} editable={false} />
<Card className="w-full bg-primary-500 p-8 text-white rounded-r-none"> </div>
<div className="flex flex-col gap-4"> <div className="flex flex-row justify-stretch *:w-full *:h-56 w-full p-4 pt-0 gap-4"></div>
<p className="font-bold text-4xl">Statistics Overview</p> <Card className="w-full bg-primary-500 p-8 text-white rounded-r-none">
<div className="h-[500px] w-full bg-primary-600 rounded-2xl flex flex-row p-6"> <div className="flex flex-col gap-4">
<div className="w-60 flex flex-col justify-between"> <p className="font-bold text-4xl">Statistics Overview</p>
<div className="flex flex-col"> <div className="h-[500px] w-full bg-primary-600 rounded-2xl flex flex-row p-6">
<p className="text-2xl">User Count</p> <div className="w-60 flex flex-col justify-between">
<p className="opacity-70">(past 30 days)</p> <div className="flex flex-col">
</div> <p className="text-2xl">User Count</p>
<p className="text-lg"> <p className="opacity-70">(past 30 days)</p>
Total: <span className="font-bold">2139</span> users
</p>
</div>
<div className="w-full h-full bg-white rounded-xl">
{/* TODO: Graph */}
<p className="text-black">GRAPH HERE</p>
</div> </div>
<p className="text-lg">
Total: <span className="font-bold">2139</span> users
</p>
</div> </div>
<div className="h-[500px] w-full bg-primary-600 rounded-2xl flex flex-row p-6"> <div className="w-full h-full bg-white rounded-xl">
<div className="w-60 flex flex-col justify-between"> {/* TODO: Graph */}
<p className="text-2xl">Population Distribution</p> <p className="text-black">GRAPH HERE</p>
</div>
<div className="w-full h-full bg-white rounded-xl">
{/* TODO: Graph */}
<p className="text-black">GRAPH HERE</p>
</div>
</div> </div>
</div> </div>
</Card> <div className="h-[500px] w-full bg-primary-600 rounded-2xl flex flex-row p-6">
</div> <div className="w-60 flex flex-col justify-between">
</AdministratorLayout> <p className="text-2xl">Population Distribution</p>
</div>
<div className="w-full h-full bg-white rounded-xl">
{/* TODO: Graph */}
<p className="text-black">GRAPH HERE</p>
</div>
</div>
</div>
</Card>
</div>
)} )}
</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,54 +1,64 @@
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 (
<div className="w-full h-full">
return ( <section>
<DefaultLayout> <Card className="max-w-[800px] bg-red-50 mx-auto">
<section> <CardHeader className="flex gap-3">
<Card className="max-w-[800px] bg-red-50 mx-auto"> <div className="flex flex-col">
<CardHeader className="flex gap-3"> <h2 className="text-md">Home Bill Contest</h2>
<div className="flex flex-col"> </div>
<h2 className="text-md">Home Bill Contest</h2> </CardHeader>
</div> <Divider />
</CardHeader> <CardBody>
<Divider /> <p>
<CardBody> This contest is to encourage residents to reduce the use of
<p>This contest is to encourage residents to reduce the use of electricity and water usage. electricity and water usage. This contest would be won by the
This contest would be won by the person with the lowest overall bill average. person with the lowest overall bill average. Join us in this
Join us in this important effort to create a more sustainable future for everyone. 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> Participants would be required to input and upload their bills
</CardBody> into the form to ensure integrity and honesty.{" "}
<Divider /> </p>
<CardFooter> </CardBody>
<div className="flex-col"> <Divider />
<div> <CardFooter>
<h4>Winners</h4> <div className="flex-col">
<p>There will 3 winners for each month. Each winner will receive random food vouchers.</p> <div>
<p>1st: 3 vouchers</p> <h4>Winners</h4>
<p>2nd: 2 vouchers</p> <p>
<p>3rd: 1 voucher</p> There will 3 winners for each month. Each winner will receive
</div> random food vouchers.
<div> </p>
<Button <p>1st: 3 vouchers</p>
className=" bg-red-500 dark:bg-red-700 text-white" <p>2nd: 2 vouchers</p>
size="lg" <p>3rd: 1 voucher</p>
onPress={() => { </div>
navigate("/hbcform"); <div>
}} <Button
> className=" bg-red-500 dark:bg-red-700 text-white"
<p className="font-bold">Join</p> size="lg"
</Button> onPress={() => {
</div> navigate("new-submission");
</div> }}
</CardFooter> >
</Card> <p className="font-bold">Join</p>
</section> </Button>
</DefaultLayout> </div>
) </div>
</CardFooter>
</Card>
</section>
</div>
);
} }

View File

@@ -1,183 +1,182 @@
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;
electricalBill: string; electricalBill: string;
waterBill: string; waterBill: string;
totalBill: string; totalBill: string;
noOfDependents: string; noOfDependents: string;
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 (
values: any,
{ setSubmitting, resetForm, setFieldError, setFieldValue }: any
) => {
const formData = new FormData();
formData.append("electricalBill", values.electricalBill);
formData.append("waterBill", values.waterBill);
formData.append("totalBill", values.totalBill);
formData.append("noOfDependents", values.noOfDependents);
const handleSubmit = async ( if (values.ebPicture) {
values: any, formData.append("ebPicture", values.ebPicture);
{ setSubmitting, resetForm, setFieldError, setFieldValue }: any }
) => {
const formData = new FormData();
formData.append('electricalBill', values.electricalBill);
formData.append('waterBill', values.waterBill);
formData.append('totalBill', values.totalBill);
formData.append('noOfDependents', values.noOfDependents);
if (values.ebPicture) { if (values.wbPicture) {
formData.append('ebPicture', values.ebPicture); formData.append("wbPicture", values.wbPicture);
}
try {
const response = await axios.post(
config.serverAddress + "/hbcform",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
} }
);
if (response.status === 200) {
console.log("Form created successfully:", response.data);
resetForm(); // Clear form after successful submit
setFieldValue("ebPicture", null);
setFieldValue("wbPicture", null);
navigate(-1);
} else {
console.error("Error creating form:", response.statusText);
}
} catch (error: any) {
if (error.response && error.response.data && error.response.data.errors) {
const errors = error.response.data.errors;
Object.keys(errors).forEach((key) => {
setFieldError(key, errors[key]);
});
} else {
console.error("Unexpected error:", error);
}
} finally {
setSubmitting(false);
}
};
if (values.wbPicture) { return (
formData.append('wbPicture', values.wbPicture); <div className="w-full h-full">
} <section className="w-7/12 mx-auto">
<Button variant="light" onPress={() => navigate(-1)}>
try { <ArrowUTurnLeftIcon />
const response = await axios.post(config.serverAddress + "/hbcform", formData, { </Button>
headers: { </section>
'Content-Type': 'multipart/form-data' <section className="w-7/12 mx-auto p-5 bg-red-100 border border-none rounded-2xl h-600px">
} <Formik
}); initialValues={initialValues}
if (response.status === 200) { validationSchema={validationSchema}
console.log("Form created successfully:", response.data); onSubmit={handleSubmit}
resetForm(); // Clear form after successful submit >
setFieldValue('ebPicture', null); {({ isValid, dirty, isSubmitting, setFieldValue }) => (
setFieldValue('wbPicture', null); <Form>
navigate("/contest"); <div className="flex flex-col gap-5">
} else { <div className="flex flex-row gap-10">
console.error("Error creating form:", response.statusText); <div className="flex flex-col gap-5">
} <NextUIFormikInput
} catch (error: any) { label="Electrical Bill"
if (error.response && error.response.data && error.response.data.errors) { name="electricalBill"
const errors = error.response.data.errors; type="text"
Object.keys(errors).forEach((key) => { placeholder="$"
setFieldError(key, errors[key]); labelPlacement="inside"
}); />
} else { <NextUIFormikInput
console.error("Unexpected error:", error); label="Water Bill"
} name="waterBill"
} finally { type="text"
setSubmitting(false); placeholder="$"
} labelPlacement="inside"
}; />
<NextUIFormikInput
return ( label="Total Bill"
<DefaultLayout> name="totalBill"
<section className="w-7/12 mx-auto"> type="text"
<Button placeholder="$"
variant="light" labelPlacement="inside"
onPress={() => navigate(-1)} />
> <NextUIFormikInput
<ArrowUTurnLeftIcon /> label="Number of dependents"
</Button> name="noOfDependents"
</section> type="text"
<section className="w-7/12 mx-auto p-5 bg-red-100 border border-none rounded-2xl h-600px"> placeholder="0"
<Formik labelPlacement="inside"
initialValues={initialValues} />
validationSchema={validationSchema} </div>
onSubmit={handleSubmit} <div className="flex flex-row gap-8 max-w-xs h-[500px]">
> <InsertImage
{({ isValid, dirty, isSubmitting, setFieldValue }) => ( onImageSelected={(file) => {
<Form> setFieldValue("ebPicture", file);
<div className="flex flex-col gap-5"> }}
<div className="flex flex-row gap-10"> />
<div className="flex flex-col gap-5"> <InsertImage
<NextUIFormikInput onImageSelected={(file) => {
label="Electrical Bill" setFieldValue("wbPicture", file);
name="electricalBill" }}
type="text" />
placeholder="$" </div>
labelPlacement="inside" </div>
/> <div>
<NextUIFormikInput <Button
label="Water Bill" type="submit"
name="waterBill" className="bg-red-500 dark:bg-red-700 text-white"
type="text" isDisabled={!isValid || !dirty || isSubmitting}
placeholder="$" >
labelPlacement="inside" <p>Submit</p>
/> </Button>
<NextUIFormikInput </div>
label="Total Bill" </div>
name="totalBill" </Form>
type="text" )}
placeholder="$" </Formik>
labelPlacement="inside" </section>
/> </div>
<NextUIFormikInput );
label="Number of dependents"
name="noOfDependents"
type="text"
placeholder="0"
labelPlacement="inside"
/>
</div>
<div className="flex flex-row gap-8 max-w-xs h-[500px]">
<InsertImage
onImageSelected={(file) => {
setFieldValue('ebPicture', file);
}}
/>
<InsertImage
onImageSelected={(file) => {
setFieldValue('wbPicture', file);
}}
/>
</div>
</div>
<div>
<Button
type="submit"
className="bg-red-500 dark:bg-red-700 text-white"
isDisabled={!isValid || !dirty || isSubmitting}
>
<p>Submit</p>
</Button>
</div>
</div>
</Form>
)}
</Formik>
</section>
</DefaultLayout>
);
} }

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,196 +1,200 @@
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 {
Button, Button,
Avatar, Avatar,
Dropdown, Dropdown,
DropdownTrigger, DropdownTrigger,
DropdownMenu, DropdownMenu,
DropdownItem, DropdownItem,
Chip, Chip,
Modal, Modal,
ModalContent, ModalContent,
ModalHeader, ModalHeader,
ModalBody, ModalBody,
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 {
title: string; title: string;
postImage: Blob; postImage: Blob;
content: string; content: string;
tags: string; tags: string;
id: number; id: number;
} }
const PostPage: React.FC = () => { const PostPage: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
const [post, setPost] = useState<Post | null>(null); const [post, setPost] = useState<Post | null>(null);
const { isOpen, onOpen, onOpenChange } = useDisclosure(); const { isOpen, onOpen, onOpenChange } = useDisclosure();
const [selectedPost, setSelectedPost] = useState<Post | null>(null); const [selectedPost, setSelectedPost] = useState<Post | null>(null);
useEffect(() => { useEffect(() => {
if (id) { if (id) {
instance.get(`${config.serverAddress}/post/${id}`).then((res) => { instance.get(`${config.serverAddress}/post/${id}`).then((res) => {
setPost(res.data); setPost(res.data);
}); });
}
}, [id]);
if (!post) {
return <div className="flex justify-center min-h-screen"><Spinner label="Loading..." color="danger" /></div>;
} }
}, [id]);
const handleDeleteClick = (post: Post) => { if (!post) {
setSelectedPost(post);
onOpen();
};
const handleDeleteConfirm = async () => {
if (selectedPost) {
try {
await instance.delete(
config.serverAddress + `/post/${selectedPost.id}`
);
onOpenChange();
} catch (error) {
console.error("Error deleting post:", error);
}
}
};
return ( return (
<DefaultLayout> <div className="flex justify-center min-h-screen">
<section className="flex"> <Spinner label="Loading..." color="danger" />
<div className="w-2/12 flex justify-end"> </div>
<Button );
variant="light" }
onPress={() => {
navigate(-1); const handleDeleteClick = (post: Post) => {
}} setSelectedPost(post);
> onOpen();
<ArrowUTurnLeftIcon /> };
</Button> const handleDeleteConfirm = async () => {
if (selectedPost) {
try {
await instance.delete(
config.serverAddress + `/post/${selectedPost.id}`
);
onOpenChange();
} catch (error) {
console.error("Error deleting post:", error);
}
}
};
return (
<div className="w-full h-full">
<section className="flex">
<div className="w-2/12 flex justify-end">
<Button
variant="light"
onPress={() => {
navigate(-1);
}}
>
<ArrowUTurnLeftIcon />
</Button>
</div>
<div className="flex flex-row w-full gap-4 mx-auto ">
<div className="flex flex-col gap-8 w-full">
<div className="flex flex-col gap-4">
<section
className="flex flex-row gap-4 bg-primary-50 dark:bg-primary-950 border border-none rounded-2xl p-4"
key={post.id}
>
<div>
<Avatar
src="https://pbs.twimg.com/media/GOva9x5a0AAK8Bn?format=jpg&name=large"
size="lg"
/>
</div> </div>
<div className="flex flex-row w-full gap-4 mx-auto "> <div className="flex flex-col gap-8 w-full">
<div className="flex flex-col gap-8 w-full"> <div className="h-full flex flex-col gap-4">
<div className="flex flex-col gap-4"> <div className="flex flex-row justify-between">
<section <div className="flex flex-col">
className="flex flex-row gap-4 bg-primary-50 dark:bg-primary-950 border border-none rounded-2xl p-4" <p className="text-xl font-bold">{post.title}</p>
key={post.id}> <p className="text-md text-neutral-500">Adam</p>
<div> </div>
<Avatar <div className="flex flex-row-reverse justify-center items-center">
src="https://pbs.twimg.com/media/GOva9x5a0AAK8Bn?format=jpg&name=large" <Dropdown>
size="lg" <DropdownTrigger className="justify-center items-center">
/> <Button isIconOnly variant="light">
</div> <EllipsisHorizontalIcon />
<div className="flex flex-col gap-8 w-full"> </Button>
<div className="h-full flex flex-col gap-4"> </DropdownTrigger>
<div className="flex flex-row justify-between"> <DropdownMenu aria-label="Static Actions">
<div className="flex flex-col"> <DropdownItem
<p className="text-xl font-bold">{post.title}</p> key="edit"
<p className="text-md text-neutral-500">Adam</p> onClick={() => {
</div> navigate(`edit/${post.id}`);
<div className="flex flex-row-reverse justify-center items-center"> }}
<Dropdown> >
<DropdownTrigger className="justify-center items-center"> Edit
<Button isIconOnly variant="light"> </DropdownItem>
<EllipsisHorizontalIcon /> <DropdownItem
</Button> key="delete"
</DropdownTrigger> className="text-danger"
<DropdownMenu aria-label="Static Actions"> color="danger"
<DropdownItem onClick={() => handleDeleteClick(post)}
key="edit" >
onClick={() => { Delete
navigate(`/editPost/${post.id}`); </DropdownItem>
}}> </DropdownMenu>
Edit </Dropdown>
</DropdownItem> </div>
<DropdownItem </div>
key="delete" <div>
className="text-danger" <p>{post.content}</p>
color="danger" </div>
onClick={() => handleDeleteClick(post)} <div>
> <p>Image</p>
Delete {/* {userInformation && (
</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
</div>
<div>
<p>{post.content}</p>
</div>
<div>
<p>Image</p>
{/* {userInformation && (
<UserPostImage <UserPostImage
userId={userInformation} userId={userInformation}
editable={true} editable={true}
/> />
)} */} )} */}
</div> </div>
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="flex flex-row gap-2"> <div className="flex flex-row gap-2">
<Chip>Tag 1</Chip> <Chip>Tag 1</Chip>
<Chip>Tag 2</Chip> <Chip>Tag 2</Chip>
</div> </div>
<div className="flex flex-row"> <div className="flex flex-row">
<Button variant="light" isIconOnly> <Button variant="light" isIconOnly>
<HandThumbsUpIcon /> <HandThumbsUpIcon />
</Button> </Button>
<Button variant="light" isIconOnly> <Button variant="light" isIconOnly>
<ChatBubbleOvalLeftEllipsisIcon /> <ChatBubbleOvalLeftEllipsisIcon />
</Button> </Button>
<Button variant="light" isIconOnly> <Button variant="light" isIconOnly>
<EllipsisHorizontalIcon /> <EllipsisHorizontalIcon />
</Button> </Button>
</div> </div>
</div> </div>
</div>
</section>
</div>
</div> </div>
</section>
</div> </div>
<div className="w-2/12"> </div>
</div> </div>
</section> <div className="w-2/12"></div>
<Modal isOpen={isOpen} onOpenChange={onOpenChange}> </section>
<ModalContent> <Modal isOpen={isOpen} onOpenChange={onOpenChange}>
{(onClose) => ( <ModalContent>
<> {(onClose) => (
<ModalHeader className="flex flex-col gap-1"> <>
Confirm Delete <ModalHeader className="flex flex-col gap-1">
</ModalHeader> Confirm Delete
<ModalBody> </ModalHeader>
<p>Are you sure you want to delete this post?</p> <ModalBody>
</ModalBody> <p>Are you sure you want to delete this post?</p>
<ModalFooter> </ModalBody>
<Button color="danger" variant="light" onPress={onClose}> <ModalFooter>
Close <Button color="danger" variant="light" onPress={onClose}>
</Button> Close
<Button color="primary" onPress={handleDeleteConfirm}> </Button>
Confirm <Button color="primary" onPress={handleDeleteConfirm}>
</Button> Confirm
</ModalFooter> </Button>
</> </ModalFooter>
)} </>
</ModalContent> )}
</Modal> </ModalContent>
</DefaultLayout> </Modal>
); </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}`;
} }