diff --git a/client/src/components/AdministratorNavigationPanel.tsx b/client/src/components/AdministratorNavigationPanel.tsx
index 0dc8e9a..106475d 100644
--- a/client/src/components/AdministratorNavigationPanel.tsx
+++ b/client/src/components/AdministratorNavigationPanel.tsx
@@ -161,7 +161,7 @@ export default function AdministratorNavigationPanel() {
Bill Contest
}
onClickRef="ranking"
/>
diff --git a/client/src/pages/Ranking.tsx b/client/src/pages/Ranking.tsx
index 79c2c2e..a56af92 100644
--- a/client/src/pages/Ranking.tsx
+++ b/client/src/pages/Ranking.tsx
@@ -1,9 +1,16 @@
import { useEffect, useState } from 'react';
import config from '../config';
import instance from '../security/http';
-import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, SortDescriptor, Button } from '@nextui-org/react';
+import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, SortDescriptor, Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@nextui-org/react';
import { EmailIcon, TrashDeleteIcon } from '../icons';
+interface User {
+ id: string;
+ firstName: string;
+ lastName: string;
+ email: string;
+}
+
interface FormData {
id: number;
electricalBill: number;
@@ -18,29 +25,39 @@ interface FormData {
export default function Ranking() {
const [formData, setFormData] = useState([]);
+ const [userData, setUserData] = useState([]);
const [sortDescriptor, setSortDescriptor] = useState({
column: 'avgBill',
direction: 'ascending',
});
+ const [isEmailModalOpen, setIsEmailModalOpen] = useState(false);
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
+ const [selectedUser, setSelectedUser] = useState<{ email: string, name: string }>({ email: '', name: '' });
+ const [selectedFormId, setSelectedFormId] = useState(null);
useEffect(() => {
- const getFormData = async () => {
+ const fetchData = async () => {
try {
- const response = await instance.get(`${config.serverAddress}/hbcform`);
- const processedData = response.data.map((data: FormData) => ({
+ // Fetch form data
+ const formResponse = await instance.get(`${config.serverAddress}/hbcform`);
+ const processedFormData = formResponse.data.map((data) => ({
...data,
electricalBill: Number(data.electricalBill),
waterBill: Number(data.waterBill),
totalBill: Number(data.totalBill),
avgBill: Number(data.avgBill),
}));
- setFormData(processedData);
+ setFormData(processedFormData);
+
+ // Fetch user data
+ const userResponse = await instance.get(`${config.serverAddress}/users/all`);
+ setUserData(userResponse.data);
} catch (error) {
- console.log("Failed to fetch form data");
+ console.log("Failed to fetch data");
}
};
- getFormData();
+ fetchData();
}, []);
const sortFormData = (list: FormData[], descriptor: SortDescriptor) => {
@@ -71,6 +88,49 @@ export default function Ranking() {
const sortedFormData = sortFormData(formData, sortDescriptor);
+ // Combine form data with user information
+ const combinedData = sortedFormData.map((data) => {
+ const user = userData.find((user) => user.id === data.userId);
+ return {
+ ...data,
+ userName: user ? `${user.firstName} ${user.lastName}` : 'Unknown User',
+ userEmail: user ? user.email : 'Unknown Email',
+ };
+ });
+
+ const handleEmailClick = (email: string, name: string) => {
+ setSelectedUser({ email, name });
+ setIsEmailModalOpen(true);
+ };
+
+ const sendEmail = () => {
+ const subject = "Home Bill Contest";
+ const body = `Dear ${selectedUser.name},
+ \nPlease submit another submission for the home bill contest with correct documents.
+ \nThank you for your cooperation.
+ \nYour Sincerely,
+ Admin from Ecoconnect.gov`;
+ window.location.href = `mailto:${selectedUser.email}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
+ setIsEmailModalOpen(false);
+ };
+
+ const handleDeleteClick = (id: number) => {
+ setSelectedFormId(id);
+ setIsDeleteModalOpen(true);
+ };
+
+ const deleteForm = async () => {
+ if (selectedFormId === null) return;
+ try {
+ await instance.delete(`${config.serverAddress}/hbcform/${selectedFormId}`);
+ setFormData(formData.filter((data) => data.id !== selectedFormId));
+ setSelectedFormId(null);
+ setIsDeleteModalOpen(false);
+ } catch (error) {
+ console.error("Failed to delete form entry:", error);
+ }
+ };
+
return (
Form Data
@@ -78,6 +138,8 @@ export default function Ranking() {
User ID
+ User Name
+ User Email
Electrical Bill
Water Bill
Total Bill
@@ -90,9 +152,11 @@ export default function Ranking() {
Actions
- {sortedFormData.map((data) => (
+ {combinedData.map((data) => (
{data.userId}
+ {data.userName}
+ {data.userEmail}
${data.electricalBill.toFixed(2)}
${data.waterBill.toFixed(2)}
${data.totalBill.toFixed(2)}
@@ -105,14 +169,56 @@ export default function Ranking() {
{data.wbPicture &&
}
-
-
+
+
))}
+ {/* Email Confirmation Modal */}
+
+
+ {(onClose) => (
+ <>
+ Send Email
+
+ Are you sure you want to send this email to {selectedUser.email}?
+
+
+
+
+
+ >
+ )}
+
+
+ {/* Delete Confirmation Modal */}
+
+
+ {(onClose) => (
+ <>
+ Delete Entry
+
+ Are you sure you want to delete this entry?
+
+
+
+
+
+ >
+ )}
+
+
);
}
diff --git a/server/routes/hbcform.js b/server/routes/hbcform.js
index ba7de79..15f5601 100644
--- a/server/routes/hbcform.js
+++ b/server/routes/hbcform.js
@@ -107,4 +107,21 @@ router.get("/wbPicture/:id", async (req, res) => {
}
});
+router.delete("/:id", async (req, res) => {
+ let id = req.params.id;
+ try {
+ const result = await HBCform.destroy({ where: { id } });
+ if (result === 0) {
+ // No rows were deleted
+ res.sendStatus(404);
+ } else {
+ // Successfully deleted
+ res.sendStatus(204);
+ }
+ } catch (err) {
+ console.error("Error deleting form entry:", err);
+ res.status(500).json({ message: "Failed to delete form entry", error: err });
+ }
+});
+
module.exports = router;
\ No newline at end of file