diff --git a/client/app/auth/change-password/page.tsx b/client/app/auth/change-password/page.tsx index d42fea2..4138d97 100644 --- a/client/app/auth/change-password/page.tsx +++ b/client/app/auth/change-password/page.tsx @@ -16,14 +16,14 @@ import { setCookie } from "@/lib/cookieFunctions"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; +import ReCAPTCHA from "react-google-recaptcha"; export default function ChangePassword() { const router = useRouter(); const { changePass, setPassChangeData } = useChangePass(); - const [correctCaptcha, setCorrectCaptcha] = useState(""); - const [userCaptcha, setUserCaptcha] = useState(""); + const [isVerified, setIsCaptchaVerified] = useState(); const [oldPassword, setOldPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); @@ -33,8 +33,8 @@ export default function ChangePassword() { let timer = setInterval(() => { setTime((time) => { if (time === 0) { - clearInterval(timer); - alert("Time Expired!"); + clearInterval(timer); + alert("Time Expired!"); router.push("/dashboard"); return 0; } else return time - 0.5; @@ -44,15 +44,15 @@ export default function ChangePassword() { async function submitForm() { setPassChangeData({ oldPassword, newPassword }); - correctCaptcha === userCaptcha && - (await changePass()) && - router.push("/dashboard"); - correctCaptcha !== userCaptcha && alert("Invalid Captcha!"); + isVerified && (await changePass()) && router.push("/dashboard"); + !isVerified && alert("Invalid Captcha!"); } return (
- + Change Password @@ -62,7 +62,7 @@ export default function ChangePassword() { {`${time % 60}`.padStart(2, "0")} mins. - +
@@ -84,10 +84,12 @@ export default function ChangePassword() { required />
- +
+ +
diff --git a/client/app/auth/reset-password/initiate/forgetPasswordInitiate.tsx b/client/app/auth/reset-password/initiate/forgetPasswordInitiate.tsx index a9266a7..bcf9fff 100644 --- a/client/app/auth/reset-password/initiate/forgetPasswordInitiate.tsx +++ b/client/app/auth/reset-password/initiate/forgetPasswordInitiate.tsx @@ -7,14 +7,20 @@ import { Label } from "@/components/ui/label"; import { useRouter } from "next/navigation"; import useForgetPassInitiate from "@/hooks/auth/useForgetPassInitiate"; -import { useContext } from "react"; +import { useContext, useState } from "react"; +import ReCAPTCHA from "react-google-recaptcha"; function ForgetPassInitiateForm() { const { userEmail, setUserEmail, initiate } = useForgetPassInitiate(); + const [isCaptchaVerified, setIsCaptchaVerified] = useState(); const router = useRouter(); async function handleFormSubmit(e: React.FormEvent) { e.preventDefault(); + if (!isCaptchaVerified) { + alert("Please verify that you are not a robot."); + return; + } const success = await initiate(); success && router.push("/auth/reset-password/confirm" + "?email=" + userEmail); } @@ -34,7 +40,8 @@ function ForgetPassInitiateForm() { } required /> -
+ + diff --git a/client/components/dashboard-componenets/mainContent/systemAdminContents/Roles.tsx b/client/components/dashboard-componenets/mainContent/systemAdminContents/Roles.tsx index 8471bc4..8950880 100644 --- a/client/components/dashboard-componenets/mainContent/systemAdminContents/Roles.tsx +++ b/client/components/dashboard-componenets/mainContent/systemAdminContents/Roles.tsx @@ -1,7 +1,7 @@ import { Button } from "@/components/ui/button"; import { Cog, UserRoundCog } from "lucide-react"; import EmptyFillContainer from "../../cards/EmptyFillContainer"; -import { RoleCreateModal } from "@/components/modals/RoleModal"; +import { RoleCreateModal } from "@/components/modals/userControls/RoleModal"; export default function AdminRolesManagementPanel() { return ( diff --git a/client/components/dashboard-componenets/mainContent/systemAdminContents/System.tsx b/client/components/dashboard-componenets/mainContent/systemAdminContents/System.tsx index a2888b0..2ef7807 100644 --- a/client/components/dashboard-componenets/mainContent/systemAdminContents/System.tsx +++ b/client/components/dashboard-componenets/mainContent/systemAdminContents/System.tsx @@ -1,11 +1,13 @@ import { Button } from "@/components/ui/button"; import EmptyFillContainer from "../../cards/EmptyFillContainer"; import { Plus, Truck } from "lucide-react"; -import { StsCreateModal } from "../../../modals/StsModal"; +import { StsCreateModal } from "../../../modals/stsControl/StsModal"; import { VehicleCreateModal } from "@/components/modals/VehicleModal"; -import { LandfillCreateModal } from "@/components/modals/LandfillModal"; +import { LandfillCreateModal } from "@/components/modals/landfillControl/LandfillModal"; import UserListTable from "@/components/dataTables/UserList"; import STSListTable from "@/components/dataTables/STSList"; +import LandFillListTable from "@/components/dataTables/LandFillList"; +import AllVehicleList from "@/components/dataTables/AllVehicleList"; export default function AdminSystemDataPanel() { return ( @@ -47,16 +49,16 @@ export default function AdminSystemDataPanel() {
-
-
+
+
-
- VEICLE LIST -
-
- LANDFILL LIST -
+
+ +
+
+ +
diff --git a/client/components/dashboard-componenets/mainContent/systemAdminContents/Users.tsx b/client/components/dashboard-componenets/mainContent/systemAdminContents/Users.tsx index 3e68718..ea3bf20 100644 --- a/client/components/dashboard-componenets/mainContent/systemAdminContents/Users.tsx +++ b/client/components/dashboard-componenets/mainContent/systemAdminContents/Users.tsx @@ -3,7 +3,7 @@ import * as React from "react"; import useAddNewUser from "@/hooks/user_data/useAddNewUser"; -import { AddNewUserModal } from "@/components/modals/AddNewUserModal"; +import { AddNewUserModal } from "@/components/modals/userControls/AddNewUserModal"; import UserListTable from "@/components/dataTables/UserList"; export default function AdminUserManagementPanel() { diff --git a/client/components/dataTables/AllVehicleList.tsx b/client/components/dataTables/AllVehicleList.tsx new file mode 100644 index 0000000..5af54f8 --- /dev/null +++ b/client/components/dataTables/AllVehicleList.tsx @@ -0,0 +1,361 @@ +"use client"; + +import * as React from "react"; +import { + CaretSortIcon, + ChevronDownIcon, + DotsHorizontalIcon, +} from "@radix-ui/react-icons"; + +import { Button } from "@/components/ui/button"; + +import { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; + +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import useGetAllUser from "@/hooks/user_data/useGetAllUser"; +import { DeleteUserModal } from "../modals/userControls/DeleteUserModal"; +import { Copy, EditIcon } from "lucide-react"; +import { EditUserModal } from "../modals/userControls/EditUserInfoModal"; +import gettAllRoles from "@/hooks/user_data/useGetAllRole"; +import { roleList } from "@/data/roles"; +import useGetAllSTS from "@/hooks/dataQuery/useGetAllSTS"; +import { EditSTSInfoModal } from "../modals/stsControl/EditSTSInfoModal"; +import { DeleteSTSModal } from "../modals/stsControl/DeleteSTSModal"; +import useVehicleList from "@/hooks/vehicles/useVehiclesData"; +import useVehicleListForSTS from "@/hooks/vehicles/useGetVeicleForSTS"; +import { DeleteVehicleModalForSTS } from "../modals/DeleteVehicleModalForSTS"; +import useGetAllVehicleList from "@/hooks/vehicles/useGetAllVehicleList"; +import { DeleteVehicleModal } from "../modals/vehicleControl/DeleteVehicleModal"; + +type Vehicle = { + id: string, + vehicleNumber: string, + vehicleType: string, + capacity: string, + loadedFuelCostPerKm: string, + unloadedFuelCostPerKm: string, + landFillId: string, + landFillName: string, +}; + +export const columns: ColumnDef[] = [ + { + accessorKey: "vehicleNumber", + header: ({ column }) => { + return ( +
+ +
+ ); + }, + cell: ({ row }) => ( +
{row.getValue("vehicleNumber")}
+ ), + }, + { + accessorKey: "vehicleType", + header: ({ column }) => { + return ( +
+ +
+ ); + }, + cell: ({ row }) => ( +
+ {row.getValue("vehicleType")} +
+ ), + }, + { + accessorKey: "capacity", + header: ({ column }) => { + return ( +
+ +
+ ); + }, + cell: ({ row }) => ( +
{row.getValue("capacity") + " Ton"}
+ ), + }, + { + accessorKey: "landFillName", + header: ({ column }) => { + return ( +
+ +
+ ); + }, + cell: ({ row }) => ( +
{row.getValue("landFillName")}
+ ), + }, + { + accessorKey: "loadedFuelCostPerKm", + header: ({ column }) => { + return ( +
+ +
+ ); + }, + cell: ({ row }) => ( +
{row.getValue("loadedFuelCostPerKm")}
+ ), + }, + { + accessorKey: "unloadedFuelCostPerKm", + header: ({ column }) => { + return ( +
+ +
+ ); + }, + cell: ({ row }) => ( +
{row.getValue("unloadedFuelCostPerKm")}
+ ), + }, + { + id: "actions", + enableHiding: false, + cell: ({ row }) => { + const vehicle: Vehicle = row.original; + + return ( +
+ + {/* */} + {/* */} +
+ ); + }, + }, +]; + +export default function AllVehicleList() { + const [data, setData] = React.useState([]); + const { getVehicleList, vehicleList } = useGetAllVehicleList(); + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState( + [] + ); + const [columnVisibility, setColumnVisibility] = + React.useState({}); + const [rowSelection, setRowSelection] = React.useState({}); + + React.useEffect(() => { + getVehicleList(); + }, []); + + React.useEffect(() => { + setData(vehicleList); + }, [vehicleList]); + + const table = useReactTable({ + data, + columns, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }); + return ( + <> +
MANAGE ALL VEHICLES
+
+ + table.getColumn("vehicleNumber")?.setFilterValue(event.target.value) + } + className="max-w-sm" + /> + + + + + + {table + .getAllColumns() + .filter((column) => column.getCanHide()) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ); + })} + + +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ); + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+
+ {table.getFilteredSelectedRowModel().rows.length} of{" "} + {table.getFilteredRowModel().rows.length} row(s) selected. +
+
+ + +
+
+ + ); +} diff --git a/client/components/dataTables/LandFillList.tsx b/client/components/dataTables/LandFillList.tsx new file mode 100644 index 0000000..72ce361 --- /dev/null +++ b/client/components/dataTables/LandFillList.tsx @@ -0,0 +1,277 @@ +"use client"; + +import * as React from "react"; +import { + CaretSortIcon, + ChevronDownIcon, + DotsHorizontalIcon, +} from "@radix-ui/react-icons"; + +import { Button } from "@/components/ui/button"; + +import { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; + +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import useGetAllUser from "@/hooks/user_data/useGetAllUser"; +import { DeleteUserModal } from "../modals/userControls/DeleteUserModal"; +import { Copy, EditIcon, Plus } from "lucide-react"; +import { EditUserModal } from "../modals/userControls/EditUserInfoModal"; +import gettAllRoles from "@/hooks/user_data/useGetAllRole"; +import { roleList } from "@/data/roles"; +import useGetAllSTS from "@/hooks/dataQuery/useGetAllSTS"; +import { EditSTSInfoModal } from "../modals/stsControl/EditSTSInfoModal"; +import { DeleteSTSModal } from "../modals/stsControl/DeleteSTSModal"; +import { ViewSTSInfoModal } from "../modals/stsControl/ViewSTSInfoModal"; +import { StsCreateModal } from "../modals/stsControl/StsModal"; +import useGetAllLandfill from "@/hooks/dataQuery/useGetAllLandfill"; +import { ViewLandFIllInfoModal } from "../modals/landfillControl/ViewLandfillInfoModal"; +import { EditLandfillInfoModal } from "../modals/landfillControl/EditLandfillInfoModal"; +import { DeleteLandfillModal } from "../modals/landfillControl/DeleteLandfillModal"; + +export type LandFill = { + id: string; + name: string; + capacity: string; + latitude: string; + longitude: string; + manager: string[]; +}; + +export const columns: ColumnDef[] = [ + { + accessorKey: "name", + header: ({ column }) => { + return ( +
+ +
+ ); + }, + cell: ({ row }) => ( +
{row.getValue("name")}
+ ), + }, + { + accessorKey: "capacity", + header: ({ column }) => { + return ( +
+ +
+ ); + }, + cell: ({ row }) => ( +
{row.getValue("capacity")}
+ ), + }, + { + id: "actions", + enableHiding: false, + cell: ({ row }) => { + const landfill: LandFill = row.original; + + return ( +
+ + + +
+ ); + }, + }, +]; + +export default function LandFillListTable() { + const [data, setData] = React.useState([]); + const { fetchAllLandfills, landFillData } = useGetAllLandfill(); + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState( + [] + ); + const [columnVisibility, setColumnVisibility] = + React.useState({}); + const [rowSelection, setRowSelection] = React.useState({}); + + React.useEffect(() => { + fetchAllLandfills(); + }, []); + + React.useEffect(() => { + setData(landFillData); + }, [landFillData]); + + const table = useReactTable({ + data, + columns, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }); + return ( + <> +
MANAGE ALL LANDFILLS
+
+ + table.getColumn("name")?.setFilterValue(event.target.value) + } + className="max-w-sm" + /> + + + + + + {table + .getAllColumns() + .filter((column) => column.getCanHide()) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ); + })} + + +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ); + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+
+ Total {table.getFilteredRowModel().rows.length} row(s) loaded. +
+
+ + +
+
+ + ); +} diff --git a/client/components/dataTables/STSList.tsx b/client/components/dataTables/STSList.tsx index e97343d..ad53c01 100644 --- a/client/components/dataTables/STSList.tsx +++ b/client/components/dataTables/STSList.tsx @@ -41,14 +41,16 @@ import { TableRow, } from "@/components/ui/table"; import useGetAllUser from "@/hooks/user_data/useGetAllUser"; -import { DeleteUserModal } from "../modals/DeleteUserModal"; -import { Copy, EditIcon } from "lucide-react"; -import { EditUserModal } from "../modals/EditUserInfoModal"; +import { DeleteUserModal } from "../modals/userControls/DeleteUserModal"; +import { Copy, EditIcon, Plus } from "lucide-react"; +import { EditUserModal } from "../modals/userControls/EditUserInfoModal"; import gettAllRoles from "@/hooks/user_data/useGetAllRole"; import { roleList } from "@/data/roles"; import useGetAllSTS from "@/hooks/dataQuery/useGetAllSTS"; -import { EditSTSInfoModal } from "../modals/EditSTSInfoModal"; -import { DeleteSTSModal } from "../modals/DeleteSTSModal"; +import { EditSTSInfoModal } from "../modals/stsControl/EditSTSInfoModal"; +import { DeleteSTSModal } from "../modals/stsControl/DeleteSTSModal"; +import { ViewSTSInfoModal } from "../modals/stsControl/ViewSTSInfoModal"; +import { StsCreateModal } from "../modals/stsControl/StsModal"; export type STS = { id: string; @@ -57,6 +59,7 @@ export type STS = { capacity: string; latitude: string; longitude: string; + manager: string[]; }; export const columns: ColumnDef[] = [ @@ -129,9 +132,10 @@ export const columns: ColumnDef[] = [ const sts: STS = row.original; return ( -
- +
+ +
); }, @@ -177,7 +181,8 @@ export default function STSListTable() { }); return ( <> -
+
MANAGE ALL STS
+
- + @@ -265,8 +270,7 @@ export default function STSListTable() {
- {table.getFilteredSelectedRowModel().rows.length} of{" "} - {table.getFilteredRowModel().rows.length} row(s) selected. + Total {table.getFilteredRowModel().rows.length} row(s) loaded.
+ + + + + Confirm Delete STS? + + +
+

+ ID: + {landfillInfo.id} +

+

+ Name: + {landfillInfo.name} +

+

+ Capacity: + {landfillInfo.capacity} +

+

Managers:

+ {landfillInfo.manager.length === 0 ?

    NO MANAGER ASSGINED FOR THIS LandFill

: landfillInfo.manager.map((manager, index) => ( +

+     {index + 1 + "."} {manager} +

+ ))} +
+
+
+
+
+
+ + setConfirmText(e.target.value)} + required + /> +
+
+ + + +
+
+ + ); +}; diff --git a/client/components/modals/landfillControl/EditLandfillInfoModal.tsx b/client/components/modals/landfillControl/EditLandfillInfoModal.tsx new file mode 100644 index 0000000..d1469b7 --- /dev/null +++ b/client/components/modals/landfillControl/EditLandfillInfoModal.tsx @@ -0,0 +1,149 @@ +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; + +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import React, { use, useEffect, useState } from "react"; +import { EditIcon, Trash } from "lucide-react"; +import deleteUser from "@/hooks/user_data/deleteUser"; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectGroup, + SelectLabel, + SelectItem, +} from "../../ui/select"; +import editUser from "@/hooks/user_data/editUser"; +import gettAllRoles from "@/hooks/user_data/useGetAllRole"; +import { number } from "prop-types"; +import { admin, landfillManager, stsManager, unassigned } from "@/data/roles"; +import editSTS from "@/hooks/entityCreation/editSTS"; +import getUserByRole from "@/hooks/user_data/getUserByRole"; +import editLandfill from "@/hooks/entityCreation/editLandfill"; + +type LandFill = { + id: string; + name: string; + capacity: string; + latitude: string; + longitude: string; + manager: string[]; +}; + +type LandFillManager = { + id: string; + username: string; +}; + +export const EditLandfillInfoModal = ({ landfillInfo }: { landfillInfo: LandFill }) => { + const [landfillData, setLandfillData] = useState(landfillInfo); + const [landfillManagerData, setLandfillManagerData] = useState(); + const [landfillManagerList, setLandfillManagerList] = useState([]); + + const getManagerList = async () => { + const result = await getUserByRole(landfillManager); + if (result) await setLandfillManagerList(result); + }; + + useEffect(() => { + getManagerList(); + }, []); + + return ( + + + + + + + + Edit Landfill Details + + + Update Landfill information by filling out the form below. + + +
+
+
+ + + setLandfillData({ ...landfillData, name: e.target.value }) + } + className="col-span-3" + required + /> +
+
+ + + setLandfillData({ ...landfillData, capacity: e.target.value }) + } + className="col-span-3" + required + /> +
+
+ + +
+
+ + + +
+
+
+ ); +}; diff --git a/client/components/modals/LandfillModal.tsx b/client/components/modals/landfillControl/LandfillModal.tsx similarity index 98% rename from client/components/modals/LandfillModal.tsx rename to client/components/modals/landfillControl/LandfillModal.tsx index aae67c1..f625693 100644 --- a/client/components/modals/LandfillModal.tsx +++ b/client/components/modals/landfillControl/LandfillModal.tsx @@ -13,7 +13,7 @@ import { import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import React, { useState } from "react"; -import SetZone from "../maps/SetZone"; +import SetZone from "../../maps/SetZone"; import useCreateLandFill, { LandFill, } from "@/hooks/entityCreation/useCreateLandfill"; diff --git a/client/components/modals/landfillControl/ViewLandfillInfoModal.tsx b/client/components/modals/landfillControl/ViewLandfillInfoModal.tsx new file mode 100644 index 0000000..15d7462 --- /dev/null +++ b/client/components/modals/landfillControl/ViewLandfillInfoModal.tsx @@ -0,0 +1,108 @@ +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; + +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import React, { use, useEffect, useState } from "react"; +import { EditIcon, Eye, Trash } from "lucide-react"; +import deleteUser from "@/hooks/user_data/deleteUser"; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectGroup, + SelectLabel, + SelectItem, +} from "../../ui/select"; +import editUser from "@/hooks/user_data/editUser"; +import gettAllRoles from "@/hooks/user_data/useGetAllRole"; +import { number } from "prop-types"; +import { admin, landfillManager, stsManager, unassigned } from "@/data/roles"; +import editSTS from "@/hooks/entityCreation/editSTS"; +import getUserByRole from "@/hooks/user_data/getUserByRole"; + +type LandFill = { + id: string; + name: string; + capacity: string; + latitude: string; + longitude: string; + manager: string[]; +}; + +type LandFillManager = { + id: string; + username: string; +}; + +export const ViewLandFIllInfoModal = ({ landfillInfo }: { landfillInfo: LandFill }) => { + const [landFillData, setLanfillData] = useState(landfillInfo); + const [landfillManagerData, setLandfillManagerData] = useState(); + const [landfillManagerList, setLandfillManagerList] = useState([]); + + const getManagerList = async () => { + const result = await getUserByRole(landfillManager); + if (result) await setLandfillManagerList(result); + }; + + useEffect(() => { + getManagerList(); + }, []); + + return ( + + + + + + + + View STS Details + + +

Here are the description of the STS

+
+

+ ID: + {landFillData.id} +

+

+ Name: + {landFillData.name} +

+

+ Capacity: + {landFillData.capacity} +

+

+ Latitude: + {landFillData.latitude} +

+

+ Longitude: + {landFillData.longitude} +

+

Managers:

+ {landFillData.manager.length === 0 ?

    NO MANAGER ASSGINED FOR THIS LandFill

: landFillData.manager.map((manager, index) => ( +

+     {index + 1 + "."} {manager} +

+ ))} +
+
+
+
+
+ ); +}; diff --git a/client/components/modals/DeleteSTSModal.tsx b/client/components/modals/stsControl/DeleteSTSModal.tsx similarity index 87% rename from client/components/modals/DeleteSTSModal.tsx rename to client/components/modals/stsControl/DeleteSTSModal.tsx index d7c6420..52373e1 100644 --- a/client/components/modals/DeleteSTSModal.tsx +++ b/client/components/modals/stsControl/DeleteSTSModal.tsx @@ -23,6 +23,7 @@ export type STS = { capacity: string; latitude: string; longitude: string; + manager: string[]; }; export const DeleteSTSModal = ({ stsInfo }: { stsInfo: STS }) => { @@ -58,6 +59,12 @@ export const DeleteSTSModal = ({ stsInfo }: { stsInfo: STS }) => { Capacity: {stsInfo.capacity}

+

Managers:

+ {stsInfo.manager.length === 0 ?

    NO MANAGER ASSGINED FOR THIS LandFill

: stsInfo.manager.map((manager, index) => ( +

+     {index + 1 + "."} {manager} +

+ ))}
diff --git a/client/components/modals/EditSTSInfoModal.tsx b/client/components/modals/stsControl/EditSTSInfoModal.tsx similarity index 86% rename from client/components/modals/EditSTSInfoModal.tsx rename to client/components/modals/stsControl/EditSTSInfoModal.tsx index f6a9733..5f4d425 100644 --- a/client/components/modals/EditSTSInfoModal.tsx +++ b/client/components/modals/stsControl/EditSTSInfoModal.tsx @@ -22,7 +22,7 @@ import { SelectGroup, SelectLabel, SelectItem, -} from "../ui/select"; +} from "../../ui/select"; import editUser from "@/hooks/user_data/editUser"; import gettAllRoles from "@/hooks/user_data/useGetAllRole"; import { number } from "prop-types"; @@ -37,6 +37,7 @@ export type STS = { capacity: string; latitude: string; longitude: string; + manager: string[]; }; type STSManager = { @@ -71,24 +72,7 @@ export const EditSTSInfoModal = ({ stsInfo }: { stsInfo: STS }) => { Edit STS Details -
-

- ID: - {stsData.id} -

-

- Name: - {stsData.name} -

-

- Capacity: - {stsData.capacity} -

-

- Ward: - {stsData.wardNumber} -

-
+ Update STS information by filling out the form below.
@@ -140,14 +124,14 @@ export const EditSTSInfoModal = ({ stsInfo }: { stsInfo: STS }) => {
setConfirmText(e.target.value)} + required + /> +
+
+ + + + + + + ); +}; diff --git a/client/data/apiRoutes.ts b/client/data/apiRoutes.ts index ee26e02..e5c5176 100644 --- a/client/data/apiRoutes.ts +++ b/client/data/apiRoutes.ts @@ -32,4 +32,10 @@ export const apiRoutes = { delete: `${baseUrl}/rbac/`, edit: `${baseUrl}/rbac/`, }, + vehicle: { + create: `${baseUrl}/vehicles/create`, + getAll: `${baseUrl}/vehicles`, + delete: `${baseUrl}/vehicles/`, + edit: `${baseUrl}/vehicles/`, + }, } \ No newline at end of file diff --git a/client/hooks/dataQuery/useGetAllLandfill.tsx b/client/hooks/dataQuery/useGetAllLandfill.tsx new file mode 100644 index 0000000..b813f17 --- /dev/null +++ b/client/hooks/dataQuery/useGetAllLandfill.tsx @@ -0,0 +1,51 @@ +"use client"; +import { apiRoutes } from "@/data/apiRoutes"; +import { jwtToken } from "@/data/cookieNames"; +import { admin, landfillManager, stsManager, unassigned } from "@/data/roles"; +import { getCookie } from "@/lib/cookieFunctions"; +import axios from "axios"; +import { useState, useEffect, use } from "react"; + +type LandFill = { + id: string; + name: string; + capacity: string; + latitude: string; + longitude: string; + manager: string[]; + }; + +export default function useGetAllLandfill() { + const [landFillData, setLandfillData] = useState([]); + + async function fetchAllLandfills() { + try { + const res = await axios.get(apiRoutes.landfill.getAll, { + headers: { + Authorization: `Bearer ${await getCookie(jwtToken)}`, + }, + }); + const landfillList = res.data.map((sts: any) => { + return { + id: sts.id, + name: sts.name, + capacity: sts.capacity, + latitude: sts.latitude, + longitude: sts.longitude, + manager: sts.manager.map((manager: any) => manager.username), + }; + }); + await setLandfillData(landfillList); + console.log(landfillList); + } catch (error: any) { + alert("Error fetching sts data... Are you authorized?"); + console.log(error.message); + } + } + + useEffect(() => { + fetchAllLandfills(); + }, []); + + return {fetchAllLandfills, landFillData}; +} diff --git a/client/hooks/dataQuery/useGetAllSTS.tsx b/client/hooks/dataQuery/useGetAllSTS.tsx index d1ffcb6..ff3f3b0 100644 --- a/client/hooks/dataQuery/useGetAllSTS.tsx +++ b/client/hooks/dataQuery/useGetAllSTS.tsx @@ -13,6 +13,7 @@ export type STS = { capacity: string; latitude: string; longitude: string; + manager: string[]; }; export default function useGetAllSTS() { @@ -33,6 +34,7 @@ export default function useGetAllSTS() { capacity: sts.capacity, latitude: sts.latitude, longitude: sts.longitude, + manager: sts.manager.map((manager: any) => manager.username), }; }); await setSTSData(stsList); diff --git a/client/hooks/entityCreation/deleteLandfill.ts b/client/hooks/entityCreation/deleteLandfill.ts new file mode 100644 index 0000000..67ab9db --- /dev/null +++ b/client/hooks/entityCreation/deleteLandfill.ts @@ -0,0 +1,22 @@ +import { apiRoutes } from "@/data/apiRoutes"; +import { jwtToken } from "@/data/cookieNames"; +import { admin, landfillManager, stsManager, unassigned } from "@/data/roles"; +import { getCookie } from "@/lib/cookieFunctions"; +import axios from "axios"; + +export default async function deleteLandFill(landFillId: string) { + if (landFillId) { + try { + const res = await axios.delete(apiRoutes.landfill.delete + landFillId, { + headers: { + Authorization: `Bearer ${await getCookie(jwtToken)}`, + }, + }); + return "landfills deleted successfully"; + } catch (error: any) { + return error.message?.toString() || "error deleteing landfill"; + } + } + + return null; +} diff --git a/client/hooks/entityCreation/editLandfill.ts b/client/hooks/entityCreation/editLandfill.ts new file mode 100644 index 0000000..2ce7f02 --- /dev/null +++ b/client/hooks/entityCreation/editLandfill.ts @@ -0,0 +1,46 @@ +import { User } from "@/components/dataTables/UserList"; +import { apiRoutes } from "@/data/apiRoutes"; +import { jwtToken } from "@/data/cookieNames"; +import { admin, landfillManager, stsManager, unassigned } from "@/data/roles"; +import { getCookie } from "@/lib/cookieFunctions"; +import axios from "axios"; +import { STS } from "@/components/modals/stsControl/EditSTSInfoModal"; +import { LandFill } from "@/components/dataTables/LandFillList"; + +export default async function editLandfill(landfillData: LandFill, managerId: string) { + if (landfillData && managerId) { + try { + const res1 = await axios.put( + apiRoutes.user.edit + managerId, + { + landfillId: landfillData.id, + }, + { + headers: { + Authorization: `Bearer ${await getCookie(jwtToken)}`, + }, + } + ); + const {manager, ...payload} = {...landfillData}; + const res2 = await axios.put( + apiRoutes.landfill.edit + landfillData.id, + { + ...payload, + }, + { + headers: { + Authorization: `Bearer ${await getCookie(jwtToken)}`, + }, + } + ); + return "landfill updated successfully"; + } catch (error: any) { + return ( + error.message?.toString() || + "error updating landfill. You may not have the required permissions." + ); + } + } + + return null; +} diff --git a/client/hooks/entityCreation/editSTS.ts b/client/hooks/entityCreation/editSTS.ts index e9e4b73..de8df83 100644 --- a/client/hooks/entityCreation/editSTS.ts +++ b/client/hooks/entityCreation/editSTS.ts @@ -4,13 +4,13 @@ import { jwtToken } from "@/data/cookieNames"; import { admin, landfillManager, stsManager, unassigned } from "@/data/roles"; import { getCookie } from "@/lib/cookieFunctions"; import axios from "axios"; -import { STS } from "@/components/modals/EditSTSInfoModal"; +import { STS } from "@/components/modals/stsControl/EditSTSInfoModal"; -export default async function editSTS(stsData: STS, manager: string) { - if (stsData && manager) { +export default async function editSTS(stsData: STS, managerId: string) { + if (stsData && managerId) { try { const res1 = await axios.put( - apiRoutes.user.edit + manager, + apiRoutes.user.edit + managerId, { stsId: stsData.id, }, @@ -20,10 +20,11 @@ export default async function editSTS(stsData: STS, manager: string) { }, } ); + const {manager, ...payload} = {...stsData}; const res2 = await axios.put( apiRoutes.sts.edit + stsData.id, { - ...stsData, + ...payload, }, { headers: { diff --git a/client/hooks/entityCreation/useCreateLandfill.tsx b/client/hooks/entityCreation/useCreateLandfill.tsx index 79c2cbb..ae042a9 100644 --- a/client/hooks/entityCreation/useCreateLandfill.tsx +++ b/client/hooks/entityCreation/useCreateLandfill.tsx @@ -32,6 +32,7 @@ export default function useCreateLandFill() { Authorization: `Bearer ${await getCookie(jwtToken)}`, }, }); + window.location.reload(); return "Landfill Aadded successfully"; } catch (error: any) { return error.message?.toString() || "Error creating Landfill"; diff --git a/client/hooks/entityCreation/useCreateSTS.tsx b/client/hooks/entityCreation/useCreateSTS.tsx index f57dcb3..d61af0a 100644 --- a/client/hooks/entityCreation/useCreateSTS.tsx +++ b/client/hooks/entityCreation/useCreateSTS.tsx @@ -34,6 +34,7 @@ export default function useCreateSTS() { Authorization: `Bearer ${await getCookie(jwtToken)}`, }, }); + window.location.reload(); return "STS Aadded successfully"; } catch (error: any) { return error.message?.toString() || "Error creating STS"; diff --git a/client/hooks/vehicles/deleteVehiclebyId.ts b/client/hooks/vehicles/deleteVehiclebyId.ts new file mode 100644 index 0000000..1e82181 --- /dev/null +++ b/client/hooks/vehicles/deleteVehiclebyId.ts @@ -0,0 +1,23 @@ +"use client"; +import { apiRoutes } from "@/data/apiRoutes"; +import { jwtToken } from "@/data/cookieNames"; +import { admin, landfillManager, stsManager, unassigned } from "@/data/roles"; +import { getCookie } from "@/lib/cookieFunctions"; +import axios from "axios"; + +export default async function deleteVehiclebyId(id: string) { + if (id) { + try { + const res = await axios.delete(apiRoutes.vehicle.delete + id, { + headers: { + Authorization: `Bearer ${await getCookie(jwtToken)}`, + }, + }); + return "vehicle removed successfully"; + } catch (error: any) { + return error.message?.toString() || "error removing vehicle"; + } + } + + return null; +} diff --git a/client/hooks/vehicles/useGetAllVehicleList.tsx b/client/hooks/vehicles/useGetAllVehicleList.tsx new file mode 100644 index 0000000..9f4c8c9 --- /dev/null +++ b/client/hooks/vehicles/useGetAllVehicleList.tsx @@ -0,0 +1,60 @@ +import { useState } from "react"; +import axios from "axios"; +import { uri } from "@/data/constant"; +import { apiRoutes } from "@/data/apiRoutes"; +import { jwtToken } from "@/data/cookieNames"; +import { getCookie } from "@/lib/cookieFunctions"; + +type Vehicle = { + entryId: string; + id: string; + vehicleNumber: string; + vehicleType: string; + capacity: string; + loadedFuelCostPerKm: string; + unloadedFuelCostPerKm: string; + landFillId: string; + entryTime: string; + landFillName: string; + stsLattitude: string; + stsLongitude: string; + landfillLattitude: string; + landfillLongitude: string; +}; + +export default function useGetAllVehicleList() { + const [vehicleList, setVehicleList] = useState([]); // Initialize with an empty array of Vehicle objects + const [vehicleNumberList, setVehicleNumberList] = useState([]); + + async function getVehicleList() { + try { + const res = await axios.get(apiRoutes.vehicle.getAll, { + headers: { Authorization: `Bearer ${getCookie(jwtToken)}` }, + }); + // Assuming the response data is an array of vehicles + const AllVehicle: Vehicle[] = res.data.map((vehicle: any) => ({ + id: vehicle.id, + vehicleNumber: vehicle.vehicleNumber, + vehicleType: vehicle.vehicleType, + capacity: vehicle.capacity, + loadedFuelCostPerKm: vehicle.loadedFuelCostPerKm, + unloadedFuelCostPerKm: vehicle.unloadedFuelCostPerKm, + landFillId: vehicle.landFillId, + landFillName: vehicle.landFill.name, + })); + const vehicleNumbers = res.data.map( + (vehicle: Vehicle) => vehicle.vehicleNumber + ); + + setVehicleList(AllVehicle); + setVehicleNumberList(vehicleNumbers); + + return true; + } catch (error: any) { + alert(error.message?.toString() || "Error fetching vehicle list"); + return false; + } + } + + return { vehicleList, vehicleNumberList, getVehicleList }; +} diff --git a/client/package-lock.json b/client/package-lock.json index 003a621..85d3f6e 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -37,6 +37,7 @@ "react": "^18", "react-chartjs-2": "^5.2.0", "react-dom": "^18", + "react-google-recaptcha": "^3.1.0", "react-hook-form": "^7.51.1", "react-icons": "^5.0.1", "react-simple-captcha": "^9.3.1", @@ -50,6 +51,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/react-google-recaptcha": "^2.1.9", "autoprefixer": "^10.0.1", "eslint": "^8", "eslint-config-next": "14.1.4", @@ -2935,6 +2937,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-google-recaptcha": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz", + "integrity": "sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -6654,6 +6665,18 @@ "node": ">=0.10.0" } }, + "node_modules/react-async-script": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, "node_modules/react-chartjs-2": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", @@ -6713,6 +6736,18 @@ } } }, + "node_modules/react-google-recaptcha": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz", + "integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==", + "dependencies": { + "prop-types": "^15.5.0", + "react-async-script": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, "node_modules/react-hook-form": { "version": "7.51.1", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.1.tgz", diff --git a/client/package.json b/client/package.json index 43872d3..abeff23 100644 --- a/client/package.json +++ b/client/package.json @@ -38,6 +38,7 @@ "react": "^18", "react-chartjs-2": "^5.2.0", "react-dom": "^18", + "react-google-recaptcha": "^3.1.0", "react-hook-form": "^7.51.1", "react-icons": "^5.0.1", "react-simple-captcha": "^9.3.1", @@ -51,6 +52,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/react-google-recaptcha": "^2.1.9", "autoprefixer": "^10.0.1", "eslint": "^8", "eslint-config-next": "14.1.4", diff --git a/server/src/controllers/landfills.ts b/server/src/controllers/landfills.ts index 2da1cc8..821f78d 100644 --- a/server/src/controllers/landfills.ts +++ b/server/src/controllers/landfills.ts @@ -19,7 +19,11 @@ const addlandfill = errorWrapper( const getAllLandfills = errorWrapper( async (req: Request, res: Response) => { - const landfills = await prisma.landfill.findMany({}); + const landfills = await prisma.landfill.findMany({ + include: { + manager: true, + }, + }); res.status(200).json(landfills); }, { statusCode: 500, message: "Couldn't fetch landfills" } diff --git a/server/src/controllers/sts.ts b/server/src/controllers/sts.ts index ea9c116..c49973c 100644 --- a/server/src/controllers/sts.ts +++ b/server/src/controllers/sts.ts @@ -20,7 +20,11 @@ const addSTS = errorWrapper( const getAllSTS = errorWrapper( async (req: Request, res: Response) => { - const stss = await prisma.sTS.findMany({}); + const stss = await prisma.sTS.findMany({ + include: { + manager: true, + }, + }); res.json(stss); }, { statusCode: 500, message: "Couldn't fetch stss" } diff --git a/server/src/services/vehicleServices.ts b/server/src/services/vehicleServices.ts index 6fbd363..faaa4d3 100644 --- a/server/src/services/vehicleServices.ts +++ b/server/src/services/vehicleServices.ts @@ -13,7 +13,11 @@ const addVehicle = async (vehicleInfo: Vehicle) => { }; const getAllVehicles = async () => { - const vehicles = await prisma.vehicle.findMany({}); + const vehicles = await prisma.vehicle.findMany({ + include: { + landFill: true, + }, + }); return vehicles; };