Connected springboard to HBC
This commit is contained in:
@@ -727,6 +727,24 @@ export const ImageIcon = () => {
|
|||||||
d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z"
|
d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ArrowTrendingUpIcon = () => {
|
||||||
|
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="M2.25 18 9 11.25l4.306 4.306a11.95 11.95 0 0 1 5.814-5.518l2.74-1.22m0 0-5.94-2.281m5.94 2.28-2.28 5.941"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ interface User {
|
|||||||
townCouncil: string;
|
townCouncil: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FormData {
|
export interface FormData {
|
||||||
id: string;
|
id: string;
|
||||||
electricalBill: number;
|
electricalBill: number;
|
||||||
waterBill: number;
|
waterBill: number;
|
||||||
@@ -60,6 +60,17 @@ interface UserVoucher {
|
|||||||
voucherId: string;
|
voucherId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort form data based on descriptor
|
||||||
|
export const sortFormData = (list: FormData[], descriptor: SortDescriptor) => {
|
||||||
|
const { column } = descriptor;
|
||||||
|
|
||||||
|
if (column === "avgBill") {
|
||||||
|
return [...list].sort((a, b) => a.avgBill - b.avgBill);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
|
||||||
export default function Ranking() {
|
export default function Ranking() {
|
||||||
const [originalFormData, setOriginalFormData] = useState<FormData[]>([]);
|
const [originalFormData, setOriginalFormData] = useState<FormData[]>([]);
|
||||||
const [filteredFormData, setFilteredFormData] = useState<FormData[]>([]);
|
const [filteredFormData, setFilteredFormData] = useState<FormData[]>([]);
|
||||||
@@ -157,17 +168,6 @@ export default function Ranking() {
|
|||||||
setTop3Users(topUsersByTownCouncil);
|
setTop3Users(topUsersByTownCouncil);
|
||||||
}, [filteredFormData, userData]);
|
}, [filteredFormData, userData]);
|
||||||
|
|
||||||
// Sort form data based on descriptor
|
|
||||||
const sortFormData = (list: FormData[], descriptor: SortDescriptor) => {
|
|
||||||
const { column } = descriptor;
|
|
||||||
|
|
||||||
if (column === "avgBill") {
|
|
||||||
return [...list].sort((a, b) => a.avgBill - b.avgBill);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
};
|
|
||||||
|
|
||||||
const sortedFormData = sortFormData(filteredFormData, sortDescriptor);
|
const sortedFormData = sortFormData(filteredFormData, sortDescriptor);
|
||||||
|
|
||||||
const combinedData: FormDataWithUser[] = sortedFormData.map((data) => {
|
const combinedData: FormDataWithUser[] = sortedFormData.map((data) => {
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Button, Card, Link } from "@nextui-org/react";
|
import { Button, Card, Link, SortDescriptor } from "@nextui-org/react";
|
||||||
import { PencilSquareIcon } from "../icons";
|
import { ArrowTrendingUpIcon, PencilSquareIcon, VoucherIcon } from "../icons";
|
||||||
import SpringboardButton from "../components/SpringboardButton";
|
import SpringboardButton from "../components/SpringboardButton";
|
||||||
import { getTimeOfDay } from "../utilities";
|
import { getTimeOfDay } from "../utilities";
|
||||||
import { retrieveUserInformation } from "../security/users";
|
import { retrieveUserInformation } from "../security/users";
|
||||||
import UserProfilePicture from "../components/UserProfilePicture";
|
import UserProfilePicture from "../components/UserProfilePicture";
|
||||||
import instance from "../security/http";
|
import instance from "../security/http";
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
|
import { FormData, sortFormData } from "./Ranking";
|
||||||
|
|
||||||
export default function SpringboardPage() {
|
export default function SpringboardPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
let accessToken = localStorage.getItem("accessToken");
|
const accessToken = localStorage.getItem("accessToken");
|
||||||
if (!accessToken) {
|
if (!accessToken) {
|
||||||
navigate("/signin");
|
navigate("/signin");
|
||||||
}
|
}
|
||||||
const [userInformation, setUserInformation] = useState<any>();
|
const [userInformation, setUserInformation] = useState<any>();
|
||||||
const [events, setEvents] = useState<any[]>([]);
|
const [events, setEvents] = useState<any[]>([]);
|
||||||
let timeOfDay = getTimeOfDay();
|
const [userVouchers, setUserVouchers] = useState<any>();
|
||||||
|
const [contestRanking, setContestRanking] = useState<number>(-1);
|
||||||
|
const timeOfDay = getTimeOfDay();
|
||||||
|
|
||||||
let greeting = "";
|
let greeting = "";
|
||||||
if (timeOfDay === 0) {
|
if (timeOfDay === 0) {
|
||||||
@@ -34,7 +37,27 @@ export default function SpringboardPage() {
|
|||||||
if (response.accountType == 2) {
|
if (response.accountType == 2) {
|
||||||
navigate("/admin");
|
navigate("/admin");
|
||||||
}
|
}
|
||||||
|
let tmpUserInfo = response;
|
||||||
setUserInformation(response);
|
setUserInformation(response);
|
||||||
|
instance
|
||||||
|
.get("/user-vouchers/user/" + response.id)
|
||||||
|
.then((vouchersResponse) => {
|
||||||
|
setUserVouchers(vouchersResponse.data);
|
||||||
|
});
|
||||||
|
instance.get("/hbcform/").then((formResponse) => {
|
||||||
|
let rankings: FormData[] = formResponse.data;
|
||||||
|
rankings = sortFormData(rankings, {
|
||||||
|
column: "avgBill",
|
||||||
|
direction: "ascending",
|
||||||
|
});
|
||||||
|
for (let i = 0; i < rankings.length; i++) {
|
||||||
|
console.log("checking", rankings[i].userId, tmpUserInfo.id);
|
||||||
|
if (rankings[i].userId == tmpUserInfo.id) {
|
||||||
|
setContestRanking(i + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((_) => {
|
.catch((_) => {
|
||||||
navigate("/account-inaccessible");
|
navigate("/account-inaccessible");
|
||||||
@@ -116,14 +139,11 @@ export default function SpringboardPage() {
|
|||||||
<div className="w-full bg-primary-500 text-white">
|
<div className="w-full bg-primary-500 text-white">
|
||||||
{events.length > 0 && (
|
{events.length > 0 && (
|
||||||
<div className="p-10 flex flex-col gap-10">
|
<div className="p-10 flex flex-col gap-10">
|
||||||
<p className="text-3xl font-bold">Registered events</p>
|
<p className="text-3xl font-bold">Registered Events</p>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
{events.map((event, index) => (
|
{events.map((event, index) => (
|
||||||
<Card
|
<Card key={index}>
|
||||||
key={index}
|
<div className="flex flex-row justify-between *:my-auto p-3 pr-8">
|
||||||
className="bg-primary-700 border-2 border-primary-400"
|
|
||||||
>
|
|
||||||
<div className="flex flex-row justify-between *:my-auto p-2 pr-8">
|
|
||||||
<div className="flex flex-row gap-4 *:my-auto">
|
<div className="flex flex-row gap-4 *:my-auto">
|
||||||
<img
|
<img
|
||||||
className="w-20 h-20 object-cover rounded-xl"
|
className="w-20 h-20 object-cover rounded-xl"
|
||||||
@@ -166,6 +186,81 @@ export default function SpringboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="p-10">
|
||||||
|
<div className="flex flex-col gap-10">
|
||||||
|
<p className="text-3xl font-bold">Your Contest Statistics</p>
|
||||||
|
<div className="flex flex-row justify-evenly gap-40 py-20">
|
||||||
|
<div className="flex flex-col gap-16 *:mx-auto">
|
||||||
|
<div className="scale-[250%]">
|
||||||
|
<div className="flex flex-col gap-4 *:mx-auto text-center">
|
||||||
|
<div className="scale-150 text-primary-500 dark:text-primary-300">
|
||||||
|
<VoucherIcon />
|
||||||
|
</div>
|
||||||
|
{userVouchers && (
|
||||||
|
<p className="text-xs">
|
||||||
|
<span className="text-primary-500 dark:text-primary-300">
|
||||||
|
{userVouchers.userVouchers.length}
|
||||||
|
</span>{" "}
|
||||||
|
vouchers available
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
color="primary"
|
||||||
|
size="lg"
|
||||||
|
className="text-2xl"
|
||||||
|
onPress={() => {
|
||||||
|
navigate("/user-voucher");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
View
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-16 *:mx-auto">
|
||||||
|
<div className="scale-[250%]">
|
||||||
|
<div className="flex flex-col gap-4 *:mx-auto text-center">
|
||||||
|
<div className="scale-150 text-primary-500 dark:text-primary-300">
|
||||||
|
<ArrowTrendingUpIcon />
|
||||||
|
</div>
|
||||||
|
<p className="text-xs">
|
||||||
|
{!(contestRanking > 0) && (
|
||||||
|
<span className="text-primary-500 dark:text-primary-300">
|
||||||
|
No
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{contestRanking > 0 && (
|
||||||
|
<span className="text-primary-500 dark:text-primary-300">
|
||||||
|
{contestRanking}
|
||||||
|
{contestRanking == 1
|
||||||
|
? "st"
|
||||||
|
: contestRanking == 2
|
||||||
|
? "nd"
|
||||||
|
: contestRanking == 3
|
||||||
|
? "rd"
|
||||||
|
: "th"}
|
||||||
|
</span>
|
||||||
|
)}{" "}
|
||||||
|
place in the leaderboard
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
color="primary"
|
||||||
|
size="lg"
|
||||||
|
className="text-2xl"
|
||||||
|
onPress={() => {
|
||||||
|
navigate("/home-bill-contest");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
View
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -368,6 +368,8 @@ router.put("/request-reset-password/:email", async (req, res) => {
|
|||||||
{
|
{
|
||||||
resetPasswordToken: token,
|
resetPasswordToken: token,
|
||||||
resetPasswordExpireTime: Date.now() + 3600000,
|
resetPasswordExpireTime: Date.now() + 3600000,
|
||||||
|
// resetPasswordExpireTime: Date.now() + 3600000,
|
||||||
|
// GENERICMARKER
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
where: { id: user.id },
|
where: { id: user.id },
|
||||||
|
|||||||
Reference in New Issue
Block a user