Scaffolded admin page
This commit is contained in:
@@ -10,6 +10,7 @@ import CreatePostPage from "./pages/CreatePostPage";
|
||||
import EditPostPage from "./pages/EditPostPage";
|
||||
import SchedulePage from "./pages/SchedulePage";
|
||||
import EventsPage from "./pages/EventsPage";
|
||||
import AdministratorSpringboard from "./pages/AdministratorSpringboard";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
@@ -19,13 +20,13 @@ function App() {
|
||||
<Route element={<SignInPage />} path="/signin" />
|
||||
<Route element={<SpringboardPage />} path="/springboard" />
|
||||
<Route element={<ManageUserAccountPage />} path="/manage-account" />
|
||||
<Route element={<AdministratorSpringboard />} path="/admin" />
|
||||
|
||||
<Route element={<CommunityPage />} path="/community" />
|
||||
<Route element={<CreatePostPage />} path="/createPost" />
|
||||
<Route element={<EditPostPage />} path="/editPost/:id" />
|
||||
<Route element={<SchedulePage />} path="/schedule" />
|
||||
<Route element={<EventsPage />} path="/events" />
|
||||
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
|
||||
212
client/src/components/AdministratorNavigationPanel.tsx
Normal file
212
client/src/components/AdministratorNavigationPanel.tsx
Normal file
@@ -0,0 +1,212 @@
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Card,
|
||||
CircularProgress,
|
||||
ScrollShadow,
|
||||
} from "@nextui-org/react";
|
||||
import {
|
||||
CalendarDaysIcon,
|
||||
ChartBarIcon,
|
||||
ClipboardDocumentListIcon,
|
||||
ClockIcon,
|
||||
TagIcon,
|
||||
GiftTopIcon,
|
||||
ChatBubbleOvalLeftIcon,
|
||||
ChevronLeftIcon,
|
||||
} from "../icons";
|
||||
import EcoconnectFullLogo from "./EcoconnectFullLogo";
|
||||
import { retrieveUserInformation } from "../security/users";
|
||||
import { useEffect, useState } from "react";
|
||||
import config from "../config";
|
||||
import AdministratorNavigationPanelNavigationButton from "./AdministratorNavigationPanelNavigationButton";
|
||||
import EcoconnectLogo from "./EcoconnectLogo";
|
||||
|
||||
export default function AdministratorNavigationPanel() {
|
||||
const [userInformation, setUserInformation] = useState<any>();
|
||||
const [userProfileImageURL, setUserProfileImageURL] = useState("");
|
||||
const [panelVisible, setPanelVisible] = useState(true);
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
useEffect(() => {
|
||||
retrieveUserInformation().then((value) => {
|
||||
setUserInformation(value);
|
||||
setUserProfileImageURL(
|
||||
`${config.serverAddress}/users/profile-image/${value.id}`
|
||||
);
|
||||
});
|
||||
const handleScroll = () => {
|
||||
setIsScrolled(window.scrollY > 10);
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
return () => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
};
|
||||
}, []);
|
||||
return (
|
||||
<div className="h-full">
|
||||
<div
|
||||
className={`fixed transition-all top-${isScrolled ? "2" : "10"} left-2`}
|
||||
>
|
||||
<div className="bg-white rounded-full z-40">
|
||||
<Button
|
||||
isIconOnly
|
||||
size="lg"
|
||||
color="primary"
|
||||
variant="flat"
|
||||
radius="full"
|
||||
className="shadow-lg"
|
||||
onPress={() => {
|
||||
setPanelVisible(!panelVisible);
|
||||
}}
|
||||
>
|
||||
<EcoconnectLogo />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Panel */}
|
||||
<div
|
||||
className={`h-full transition-all z-50 ${
|
||||
panelVisible
|
||||
? "scale-100 opacity-100 w-[300px] px-2"
|
||||
: "w-0 scale-[98%] opacity-0 px-0"
|
||||
}`}
|
||||
></div>
|
||||
<div
|
||||
className={`fixed h-full transition-all z-50 ${
|
||||
isScrolled ? "pb-2 -mt-8" : "pb-10"
|
||||
} ${
|
||||
panelVisible
|
||||
? "scale-100 opacity-100 w-[300px] p-2"
|
||||
: "w-0 scale-[98%] opacity-0 p-0"
|
||||
}`}
|
||||
>
|
||||
<Card className="h-full w-full">
|
||||
<div className="flex flex-col h-full">
|
||||
<div className="flex flex-row justify-between bg-primary-50 dark:bg-primary-950">
|
||||
<div className="flex flex-col text-right p-4">
|
||||
<EcoconnectFullLogo />
|
||||
<p className="text-2xl text-primary-800 dark:text-primary-100 font-semibold">
|
||||
administrators
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setPanelVisible(!panelVisible);
|
||||
}}
|
||||
isIconOnly
|
||||
variant="light"
|
||||
className="rounded-tl-none rounded-br-none"
|
||||
>
|
||||
<div className="rotate-180">
|
||||
<ChevronLeftIcon />
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
{userInformation && (
|
||||
<div className="flex flex-col h-full">
|
||||
<ScrollShadow className="h-full">
|
||||
<div className="flex flex-col gap-4 p-4 *:flex *:flex-col">
|
||||
<div>
|
||||
<p className="text-sm font-bold opacity-50 pb-2">
|
||||
Events
|
||||
</p>
|
||||
<AdministratorNavigationPanelNavigationButton
|
||||
text="Events"
|
||||
icon={<CalendarDaysIcon />}
|
||||
onClickRef="#"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-bold opacity-50 pb-2">
|
||||
Community Forums
|
||||
</p>
|
||||
<AdministratorNavigationPanelNavigationButton
|
||||
text="Posts"
|
||||
icon={<ClipboardDocumentListIcon />}
|
||||
onClickRef="#"
|
||||
/>
|
||||
<AdministratorNavigationPanelNavigationButton
|
||||
text="Tags"
|
||||
icon={<TagIcon />}
|
||||
onClickRef="#"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-bold opacity-50 pb-2">
|
||||
Bill Contest
|
||||
</p>
|
||||
<AdministratorNavigationPanelNavigationButton
|
||||
text="Ranking"
|
||||
icon={<ChartBarIcon />}
|
||||
onClickRef="#"
|
||||
/>
|
||||
<AdministratorNavigationPanelNavigationButton
|
||||
text="Vouchers"
|
||||
icon={<GiftTopIcon />}
|
||||
onClickRef="#"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-bold opacity-50 pb-2">
|
||||
Karang Guni
|
||||
</p>
|
||||
<AdministratorNavigationPanelNavigationButton
|
||||
text="Schedules"
|
||||
icon={<CalendarDaysIcon />}
|
||||
onClickRef="#"
|
||||
/>
|
||||
<AdministratorNavigationPanelNavigationButton
|
||||
text="Transactions"
|
||||
icon={<ClockIcon />}
|
||||
onClickRef="#"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-bold opacity-50 pb-2">Users</p>
|
||||
<AdministratorNavigationPanelNavigationButton
|
||||
text="User Feedbacks"
|
||||
icon={<ChatBubbleOvalLeftIcon />}
|
||||
onClickRef="#"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollShadow>
|
||||
<div className="bg-primary-500 p-1">
|
||||
<Button variant="light" className="h-full w-full p-2">
|
||||
<div className="flex flex-row w-full justify-start">
|
||||
<div className="flex flex-row w-full gap-3 *:my-auto text-white">
|
||||
<Avatar src={userProfileImageURL} />
|
||||
<div className="flex flex-col h-full text-left">
|
||||
<p className="font-semibold">
|
||||
{userInformation.firstName +
|
||||
" " +
|
||||
userInformation.lastName}
|
||||
</p>
|
||||
<p className="text-sm opacity-70">
|
||||
{userInformation.email}
|
||||
</p>
|
||||
<p className="text-sm opacity-70">
|
||||
+65 {userInformation.phoneNumber}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!userInformation && (
|
||||
<div className="w-full h-full flex flex-col justify-center">
|
||||
<div className="w-full h-full flex flex-row justify-center">
|
||||
<CircularProgress />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Button } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export default function AdministratorNavigationPanelNavigationButton({
|
||||
text,
|
||||
icon,
|
||||
onClickRef,
|
||||
}: {
|
||||
text: string;
|
||||
icon: React.JSX.Element;
|
||||
onClickRef: string;
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<Button
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
navigate(onClickRef);
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row gap-2 w-full *:my-auto">
|
||||
<div className="text-primary-500">{icon}</div>
|
||||
<p>{text}</p>
|
||||
</div>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
9
client/src/components/EcoconnectFullLogo.tsx
Normal file
9
client/src/components/EcoconnectFullLogo.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
export default function EcoconnectFullLogo() {
|
||||
return (
|
||||
<img
|
||||
src="../../assets/ecoconnectFull.svg"
|
||||
alt="ecoconnect logo"
|
||||
className="h-6 dark:invert dark:hue-rotate-180"
|
||||
/>
|
||||
);
|
||||
}
|
||||
9
client/src/components/EcoconnectLogo.tsx
Normal file
9
client/src/components/EcoconnectLogo.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
export default function EcoconnectLogo() {
|
||||
return (
|
||||
<img
|
||||
src="../../assets/ecoconnectLogo.svg"
|
||||
alt="ecoconnect logo"
|
||||
className="h-6 dark:invert dark:hue-rotate-180"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import config from "../config";
|
||||
import { retrieveUserInformation } from "../security/users";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import EcoconnectFullLogo from "./EcoconnectFullLogo";
|
||||
|
||||
export default function NavigationBar() {
|
||||
let [userProfileImageURL, setUserProfileImageURL] = useState("");
|
||||
@@ -69,11 +70,7 @@ export default function NavigationBar() {
|
||||
navigate("/");
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="../../assets/ecoconnectFull.svg"
|
||||
alt="ecoconnect logo"
|
||||
className="h-6 dark:invert dark:hue-rotate-180"
|
||||
/>
|
||||
<EcoconnectFullLogo />
|
||||
</Button>
|
||||
<div className="flex flex-row *:my-auto *:text-primary-800 dark:*:text-primary-100">
|
||||
<Button
|
||||
|
||||
@@ -268,3 +268,160 @@ export const ChatBubbleOvalLeftEllipsisIcon = () => {
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ClipboardDocumentListIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="size-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75 2.25 2.25 0 0 0-.1-.664m-5.8 0A2.251 2.251 0 0 1 13.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25ZM6.75 12h.008v.008H6.75V12Zm0 3h.008v.008H6.75V15Zm0 3h.008v.008H6.75V18Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const TagIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="size-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 0 0 5.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 0 0 9.568 3Z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M6 6h.008v.008H6V6Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ChartBarIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="size-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const CalendarDaysIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="size-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5m-9-6h.008v.008H12v-.008ZM12 15h.008v.008H12V15Zm0 2.25h.008v.008H12v-.008ZM9.75 15h.008v.008H9.75V15Zm0 2.25h.008v.008H9.75v-.008ZM7.5 15h.008v.008H7.5V15Zm0 2.25h.008v.008H7.5v-.008Zm6.75-4.5h.008v.008h-.008v-.008Zm0 2.25h.008v.008h-.008V15Zm0 2.25h.008v.008h-.008v-.008Zm2.25-4.5h.008v.008H16.5v-.008Zm0 2.25h.008v.008H16.5V15Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ClockIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="size-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const GiftTopIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="size-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M12 3.75v16.5M2.25 12h19.5M6.375 17.25a4.875 4.875 0 0 0 4.875-4.875V12m6.375 5.25a4.875 4.875 0 0 1-4.875-4.875V12m-9 8.25h16.5a1.5 1.5 0 0 0 1.5-1.5V5.25a1.5 1.5 0 0 0-1.5-1.5H3.75a1.5 1.5 0 0 0-1.5 1.5v13.5a1.5 1.5 0 0 0 1.5 1.5Zm12.621-9.44c-1.409 1.41-4.242 1.061-4.242 1.061s-.349-2.833 1.06-4.242a2.25 2.25 0 0 1 3.182 3.182ZM10.773 7.63c1.409 1.409 1.06 4.242 1.06 4.242S9 12.22 7.592 10.811a2.25 2.25 0 1 1 3.182-3.182Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ChatBubbleOvalLeftIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="size-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M12 20.25c4.97 0 9-3.694 9-8.25s-4.03-8.25-9-8.25S3 7.444 3 12c0 2.104.859 4.023 2.273 5.48.432.447.74 1.04.586 1.641a4.483 4.483 0 0 1-.923 1.785A5.969 5.969 0 0 0 6 21c1.282 0 2.47-.402 3.445-1.087.81.22 1.668.337 2.555.337Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const BarsThreeIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="size-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
28
client/src/layouts/administrator.tsx
Normal file
28
client/src/layouts/administrator.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import SingaporeAgencyStrip from "../components/SingaporeAgencyStrip";
|
||||
import AdministratorNavigationPanel from "../components/AdministratorNavigationPanel";
|
||||
|
||||
export default function AdministratorLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div className="relative flex flex-col h-full">
|
||||
<SingaporeAgencyStrip />
|
||||
<div className="flex flex-row h-full ">
|
||||
<div className="h-full z-50">
|
||||
<AdministratorNavigationPanel />
|
||||
</div>
|
||||
<main className="flex-grow">{children}</main>
|
||||
</div>
|
||||
<Toaster />
|
||||
|
||||
{/*
|
||||
A div that becomes black in dark mode to cover white color parts
|
||||
of the website when scrolling past the window's original view.
|
||||
*/}
|
||||
<div className="fixed -z-50 dark:bg-black inset-0 w-full h-full"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
111
client/src/pages/AdministratorSpringboard.tsx
Normal file
111
client/src/pages/AdministratorSpringboard.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import AdministratorLayout from "../layouts/administrator";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getTimeOfDay } from "../utilities";
|
||||
import { retrieveUserInformation } from "../security/users";
|
||||
import UserProfilePicture from "../components/UserProfilePicture";
|
||||
import { Button, Card } from "@nextui-org/react";
|
||||
import { PencilSquareIcon } from "../icons";
|
||||
import EcoconnectFullLogo from "../components/EcoconnectFullLogo";
|
||||
|
||||
export default function AdministratorSpringboard() {
|
||||
const navigate = useNavigate();
|
||||
let accessToken = localStorage.getItem("accessToken");
|
||||
if (!accessToken) {
|
||||
navigate("/signin");
|
||||
}
|
||||
let [userInformation, setUserInformation] = useState<any>();
|
||||
let timeOfDay = getTimeOfDay();
|
||||
|
||||
let greeting = "";
|
||||
if (timeOfDay === 0) {
|
||||
greeting = "Good morning";
|
||||
} else if (timeOfDay === 1) {
|
||||
greeting = "Good afternoon";
|
||||
} else if (timeOfDay === 2) {
|
||||
greeting = "Good evening";
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
retrieveUserInformation()
|
||||
.then((response) => {
|
||||
setUserInformation(response);
|
||||
})
|
||||
.catch((_) => {
|
||||
navigate("/signin");
|
||||
});
|
||||
return;
|
||||
}, []);
|
||||
return (
|
||||
<div>
|
||||
{userInformation && (
|
||||
<AdministratorLayout>
|
||||
<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-col gap-3">
|
||||
<p className="text-3xl font-bold">
|
||||
{greeting}, {userInformation.firstName}.
|
||||
</p>
|
||||
<div className="flex flex-row gap-2 *:my-auto">
|
||||
<p className="text-xl">A staff member of</p>
|
||||
<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>
|
||||
<UserProfilePicture
|
||||
userId={userInformation.id}
|
||||
editable={false}
|
||||
/>
|
||||
</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">
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="font-bold text-4xl">Statistics Overview</p>
|
||||
<div className="h-[500px] w-full bg-primary-600 rounded-2xl flex flex-row p-6">
|
||||
<div className="w-60 flex flex-col justify-between">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-2xl">User Count</p>
|
||||
<p className="opacity-70">(past 30 days)</p>
|
||||
</div>
|
||||
<p className="text-lg">
|
||||
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>
|
||||
<div className="h-[500px] w-full bg-primary-600 rounded-2xl flex flex-row p-6">
|
||||
<div className="w-60 flex flex-col justify-between">
|
||||
<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>
|
||||
</AdministratorLayout>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user