diff --git a/backend/src/index.ts b/backend/src/index.ts index 228378d3..f1dcbf64 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -59,14 +59,6 @@ server.use("/notification", notificationRoutes); server.use("/violation", violationRoutes); server.use("/violator", violatorRoutes); -// server.get("/testing", async (req: Request, res: Response) => { -// try { -// res.status(200).json({ title: "Testing Complete", message: "WOWZIES" }); -// } catch (error) { -// res.sendStatus(500); -// } -// }); - // For PORT const PORT = Number(process.env.PORT) || 3000; diff --git a/backend/src/middlewares/verifyToken.ts b/backend/src/middlewares/verifyToken.ts index 39abdf39..8478a757 100644 --- a/backend/src/middlewares/verifyToken.ts +++ b/backend/src/middlewares/verifyToken.ts @@ -6,7 +6,6 @@ dotenv.config(); const verifyToken = async (req: Request, res: Response, next: NextFunction) => { const token = req.headers["authorization"]?.split(" ")[1]; - // console.log(token) if (!token) { res .status(401) @@ -19,14 +18,11 @@ const verifyToken = async (req: Request, res: Response, next: NextFunction) => { token, process.env.ACCESS_TOKEN_SECRET! ) as JwtPayload; - // console.log(payload.userId) req.user = payload.userId; - console.log(`UserId: ${req.user}`); } catch (error) { - console.log(error); res .status(403) - .json({ title: "Token Invalid", message: "Access has expired." }); + .json({ title: "Token Invalid", message: error }); return; } next(); diff --git a/backend/src/routes/auth.ts b/backend/src/routes/auth.ts index 93354ddf..d6ef970e 100644 --- a/backend/src/routes/auth.ts +++ b/backend/src/routes/auth.ts @@ -95,13 +95,11 @@ router.post("/login", validateAuth, async (req: Request, res: Response) => { // console.log(req.cookies.jwt); res.status(200).json({ accessToken, isAdmin: user.is_admin, id: user.id }); } catch (error) { - res.sendStatus(500); - console.log(error); + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); - - router.get("/refresh", async (req: Request, res: Response) => { try { const cookies = req.cookies; @@ -153,8 +151,8 @@ router.get("/refresh", async (req: Request, res: Response) => { return; } } catch (error) { - res.sendStatus(500).json({ title: "Unknown Error", message: error }); - console.log(error); + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); @@ -201,8 +199,8 @@ router.get("/logout", async (req: Request, res: Response) => { message: "Thank you for visiting, feel free to use our services again.", }); } catch (error) { - res.sendStatus(500); - console.log(error); + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); export default router; diff --git a/backend/src/routes/cars.ts b/backend/src/routes/cars.ts index f1e679ba..5885e41f 100644 --- a/backend/src/routes/cars.ts +++ b/backend/src/routes/cars.ts @@ -26,8 +26,8 @@ router.post("/check-license", async (req: Request, res: Response) => { res.status(200).json(driverFound); } catch (error) { - console.log(error); - res.sendStatus(500); + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); @@ -86,8 +86,7 @@ router.post("/add", async (req: Request, res: Response) => { }); } catch (error) { const errorMessage = (error as Error).message; - console.error("Error:", errorMessage); - res.status(500).json({ title: "Error", message: errorMessage }); + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); @@ -124,61 +123,56 @@ router.get("/get", async (req: Request, res: Response) => { res.status(200).json(cars); } catch (error: unknown) { - if (error instanceof Error) { - console.error("Error fetching cars:", error.message); - res.status(500).json({ title: "Unknown Error", message: error.message }); - return; - } else { - console.error("Unknown error:", error); - res.status(500).json({ - title: "Unknown Error", - message: "An unexpected error occurred", - }); - return; - } + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); router.patch("/update", async (req: Request, res: Response) => { - const { id, ...updates } = req.body; + try { + const { id, ...updates } = req.body; - if (!id) { - res.status(400).json({ - title: "Validation Error", - message: "License plate is required to update the record.", - }); - return; - } + if (!id) { + res.status(400).json({ + title: "Validation Error", + message: "License plate is required to update the record.", + }); + return; + } - const fields = Object.keys(updates); - const values = Object.values(updates); + const fields = Object.keys(updates); + const values = Object.values(updates); - const setClause = fields - .map((field, index) => `${field} = $${index + 1}`) - .join(", "); + const setClause = fields + .map((field, index) => `${field} = $${index + 1}`) + .join(", "); - const query = `UPDATE cars SET ${setClause} + const query = `UPDATE cars SET ${setClause} WHERE id = $${fields.length + 1} RETURNING *`; - const result = await pool.query(query, [...values, id]); + const result = await pool.query(query, [...values, id]); - if (result.rowCount === 0) { - res.status(404).json({ - title: "Not Found", - message: "Cars with the specified ID does not exist.", - }); - return; - } + if (result.rowCount === 0) { + res.status(404).json({ + title: "Not Found", + message: "Cars with the specified ID does not exist.", + }); + return; + } - const updateCar = result.rows[0]; - console.log("Car updated successfully:", updateCar); + const updateCar = result.rows[0]; + console.log("Car updated successfully:", updateCar); - res.status(200).json({ - title: "Car Updated!", - message: `Car has been updated successfully.`, - driver: updateCar, - }); + res.status(200).json({ + title: "Car Updated!", + message: `Car has been updated successfully.`, + driver: updateCar, + }); + } catch (error) { + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); + } }); router.delete("/delete", async (req: Request, res: Response) => { @@ -197,7 +191,8 @@ router.delete("/delete", async (req: Request, res: Response) => { res.status(200).json({ message: "Car Added Successfully" }); console.log("Driver deleted successfully:", car); } catch (error) { - res.status(500).json({ message: error }); + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); diff --git a/backend/src/routes/driver.ts b/backend/src/routes/driver.ts index 6eaefb95..afbe5191 100644 --- a/backend/src/routes/driver.ts +++ b/backend/src/routes/driver.ts @@ -52,16 +52,8 @@ router.post("/add", validateDriver, async (req: Request, res: Response) => { return; } catch (error) { - if (error instanceof Error) { - console.error("Error occurred:", error.message); - res.status(500).json({ title: "Server Error", message: error.message }); - } else { - console.error("Unexpected error occurred:", error); - res.status(500).json({ - title: "Server Error", - message: "An unexpected error occurred.", - }); - } + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); @@ -129,7 +121,6 @@ router.get("/get/:driverId", async (req: Request, res: Response) => { res.status(200).json({ ...foundDriver, violations, cars }); } catch (error) { const errorMessage = (error as Error).message; - console.error("Error fetching driver:", errorMessage); res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); @@ -149,20 +140,6 @@ router.patch("/update", async (req: Request, res: Response) => { license_expiration_date, } = req.body; - console.log("THIS IS THE DRIVER!"); - console.log( - id, - email, - first_name, - last_name, - middle_name, - date_of_birth, - sex, - driver_type, - license_number, - license_expiration_date - ); - if ( ![ id, @@ -210,54 +187,55 @@ router.patch("/update", async (req: Request, res: Response) => { message: `Successfully updated Driver: ${first_name} ${last_name}.`, }); } catch (error) { - console.error("Error updating driver:", error); - res.status(500).json({ - title: "Server Error", - message: "An error occurred while updating the driver.", - }); + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } }); router.delete("/delete", async (req: Request, res: Response) => { console.log("Request body:", req.body); // Log the incoming request body + try { + const { id } = req.body; - const { id } = req.body; + if (!id) { + console.error("No ID provided in the request body"); + res.status(400).json({ + title: "Validation Error", + message: "Driver ID is required to delete a record.", + }); + return; + } - if (!id) { - console.error("No ID provided in the request body"); - res.status(400).json({ - title: "Validation Error", - message: "Driver ID is required to delete a record.", - }); - return; - } + await pool.query(`DELETE FROM cars WHERE driver_id = $1 RETURNING *`, [id]); - await pool.query(`DELETE FROM cars WHERE driver_id = $1 RETURNING *`, [id]); + await pool.query(`DELETE FROM violations WHERE id = $1 RETURNING *`, [id]); - await pool.query(`DELETE FROM violations WHERE id = $1 RETURNING *`, [id]); + const resultDriver = await pool.query( + `DELETE FROM drivers WHERE id = $1 RETURNING *`, + [id] + ); - const resultDriver = await pool.query( - `DELETE FROM drivers WHERE id = $1 RETURNING *`, - [id] - ); + if (resultDriver.rowCount === 0) { + console.error("Driver not found in the database"); + res.status(404).json({ + title: "Not Found", + message: "Driver with the specified ID does not exist.", + }); + return; + } + + const deletedDriver = resultDriver.rows[0]; + console.log("Driver deleted successfully:", deletedDriver); - if (resultDriver.rowCount === 0) { - console.error("Driver not found in the database"); - res.status(404).json({ - title: "Not Found", - message: "Driver with the specified ID does not exist.", + res.status(200).json({ + title: "Driver Deleted", + message: `Driver ${deletedDriver.last_name}, ${deletedDriver.first_name} has been removed.`, + driver: deletedDriver, }); - return; + } catch (error) { + const errorMessage = (error as Error).message; + res.status(500).json({ title: "Unknown Error", message: errorMessage }); } - - const deletedDriver = resultDriver.rows[0]; - console.log("Driver deleted successfully:", deletedDriver); - - res.status(200).json({ - title: "Driver Deleted", - message: `Driver ${deletedDriver.last_name}, ${deletedDriver.first_name} has been removed.`, - driver: deletedDriver, - }); }); export default router; diff --git a/backend/src/routes/notification.ts b/backend/src/routes/notification.ts index 36f62dfc..afa8dee9 100644 --- a/backend/src/routes/notification.ts +++ b/backend/src/routes/notification.ts @@ -26,7 +26,7 @@ router.get("/get-by-user", async (req: Req, res: Response) => { res.json(notifications); } } catch (err) { - console.error("ERROR", err); + console.log(err); res.status(500).json({ title: "Server Error", message: "An unexpected error occurred while retrieving notifications", @@ -36,11 +36,12 @@ router.get("/get-by-user", async (req: Req, res: Response) => { // Create a new notification router.post("/add", async (req: Req, res: Response) => { - const { licenseNumber, message } = req.body; try { + const { driver_id, title, message } = req.body; + const { rows: drivers } = await pool.query( - "SELECT * FROM drivers WHERE license_number = $1", - [licenseNumber] + "SELECT * FROM drivers WHERE id = $1", + [driver_id] ); if (drivers.length === 0) { @@ -54,8 +55,8 @@ router.post("/add", async (req: Req, res: Response) => { const driver = await drivers[0]; const { rows: notifications } = await pool.query( - "INSERT INTO notifications (user_id, message) VALUES ($1, $2)", - [driver.id, message] + "INSERT INTO notifications (driver_id, title, message) VALUES ($1, $2, $3) RETURNING *", + [driver.id, title, message] ); if (notifications.length === 0) { diff --git a/backend/src/routes/profile.ts b/backend/src/routes/profile.ts index 0e6ec33b..0861b73b 100644 --- a/backend/src/routes/profile.ts +++ b/backend/src/routes/profile.ts @@ -24,24 +24,17 @@ router.get("/get/:id", async (req: Request, res: Response) => { [foundDriver.id] ); - res.status(200).json({ ...foundDriver, violations }); + const { rows: cars } = await pool.query( + "SELECT * FROM cars WHERE driver_id = $1", + [foundDriver.id] + ); + + res.status(200).json({ ...foundDriver, violations, cars }); } catch (error) { console.log(error); res.sendStatus(500); } }); -// router.delete("/:id", async (req: Request, res: Response) => { -// try { -// const {id} = req.params - -// const {rows: profile} = await pool.query('') - - -// } catch (error) { -// console.log(error); -// res.sendStatus(500); -// } -// }); export default router; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 00000000..dd5aa9a9 --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,105 @@ +import { BrowserRouter, Route, Routes, Navigate } from "react-router-dom"; +import "react-activity/dist/Spinner.css"; +import "react-toastify/dist/ReactToastify.css"; + +import LoginPage from "./pages/LoginPage.tsx"; +import HomePage from "./pages/HomePage.tsx"; +import SignUp from "./pages/SignUpPage.tsx"; +import AboutPage from "./pages/AboutPage.tsx"; + +import AdminLandingPage from "./pages/AdminHomePage.tsx"; +import EncodePage from "./pages/EncodePage.tsx"; +import ViolatorList from "./pages/ViolatorList.tsx"; +import DriversList from "./pages/DriverList.tsx"; +import RegisterDriver from "./pages/RegisterDriver.tsx"; +import AddDriver from "./pages/AddDriver.tsx"; +import UnauthorizedPage from "./pages/UnauthorizedPage.tsx"; +import HomepageDriver from "./components/NotificationsList.tsx"; +import RegistrationList from "./pages/RegistrationList.tsx"; +import RequireAuth from "./components/RequireAuth.tsx"; +import PersistLogin from "./components/PersistLogin.tsx"; +import Loading from "./components/Loading.tsx"; +import { LoadingContextType } from "./types/loading.types.ts"; +import useLoading from "./hooks/context-hooks/useLoading.ts"; +import ViewProfile from "./pages/ViewProfile.tsx"; +import Protocols from "./components/Policies/protocols.tsx"; +import Rules from "./components/Policies/rules.tsx"; +import ChangePassword from "./pages/ChangePassword.tsx"; +import AddViolationPage from "./pages/AddViolationPage.tsx"; +import SendNotif from "./pages/SendNotif.tsx"; + +const Main = () => { + const { appLoading }: LoadingContextType = useLoading(); + + return appLoading ? ( +
+ +
+ ) : ( + + + {/* PUBLIC ROUTES */} + } /> + } /> + + } /> + + } /> + + }> + {/* FOR ALL LOGGED IN */} + } /> + } /> + + {/* USER ROUTES */} + }> + } /> + } /> + } /> + } /> + } /> + } /> + + + {/* ADMIN ROUTES */} + }> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + + + + + ); +}; + +export default Main \ No newline at end of file diff --git a/frontend/src/components/DriversListCard.tsx b/frontend/src/components/DriversListCard.tsx index 3a022290..976fa698 100644 --- a/frontend/src/components/DriversListCard.tsx +++ b/frontend/src/components/DriversListCard.tsx @@ -8,20 +8,22 @@ const DriverListCard = ({ driver_type, license_number, }: DriverWithVandC) => { - const [isMenuOpen, setIsMenuOpen] = useState(false); const dropdownRef = useRef(null); - const { deleteDriver } = useDeleteDriver() + const { deleteDriver } = useDeleteDriver(); - const handleDeleteDriver = () => { - deleteDriver(id!) + const handleDeleteDriver = () => { + deleteDriver(id!); setIsMenuOpen(false); - } - + }; + useEffect(() => { const handleClickOutside = (event: MouseEvent) => { - if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) + ) { setIsMenuOpen(false); } }; @@ -35,59 +37,49 @@ const DriverListCard = ({ return (
+ id="row">
-
-

+
+

Name -

-

+

+

{first_name} {last_name}

-
-

Driver Type +
+

+ Driver Type

-

+

{driver_type}

-
-

+
+

License Number -

-

+

+

{license_number}

-
- +
{isMenuOpen && ( -
+
diff --git a/frontend/src/components/PreviewProfile.tsx b/frontend/src/components/PreviewProfile.tsx index 2060e9b5..82063a3d 100644 --- a/frontend/src/components/PreviewProfile.tsx +++ b/frontend/src/components/PreviewProfile.tsx @@ -13,93 +13,95 @@ const PreviewProfile = ({ }; const handleSendNotification = () => { - if(!selectedEntry) return; + if (!selectedEntry) return; navigate(`/send-notif/${selectedEntry.id}`); - }; return ( -
-
-
-

Driver Details

-
Driver's key data.
-
+
+
+

Driver Details

+
Driver's key data.
-
+
-

Last Name

-

+

+ Last Name +

+

{selectedEntry.last_name || ""}

-

First Name

-

+

+ First Name +

+

{selectedEntry.first_name || ""}

-
+
-

Sex

-

+

+ Sex +

+

{selectedEntry.sex || ""}

-

Date of Birth

-

+

+ Date of Birth +

+

{selectedEntry.date_of_birth || "MM/DD/YY"}

-

Driver Type

-

+

+ Driver Type +

+

{selectedEntry.driver_type || ""}

-
-
+
+
-

+

License Number

-

+

{selectedEntry.license_number || ""}

-
- -
-

+

License Expiration Date

-

+

{selectedEntry.license_expiration_date || ""}

-
- - -
+
+ + +
); diff --git a/frontend/src/components/SearchAndSort.tsx b/frontend/src/components/SearchAndSort.tsx index a94ebb2a..a86f3315 100644 --- a/frontend/src/components/SearchAndSort.tsx +++ b/frontend/src/components/SearchAndSort.tsx @@ -30,16 +30,16 @@ const SearchAndSort = ({ }; return ( -
+
-
-
-
+
+
+
{selectedDriver ? ( ) : ( -
+
Select a driver to see details.
)}
-
-
+
+
-
+
-

Driver's List

-
List of Drivers within the university.
+

+ Driver's List +

+

+ List of Drivers within the university. +

{ const { id } = useParams<{ id: string }>(); - const [title, setTitle] = useState(''); - const [message, setMessage] = useState(''); + const [title, setTitle] = useState(""); + const [message, setMessage] = useState(""); const { loading, driver } = useGetDriver(id!); + const { handleSendNotification } = useSendNotification(); const [formData, setFormData] = useState(null); @@ -28,9 +29,11 @@ const SendNotif: React.FC = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!formData) return; - toast.success('Message submitted for driver'); - setTitle(''); - setMessage(''); + handleSendNotification({ + driver_id: driver.id, + message: message, + title: title, + }); }; if (loading) { @@ -46,16 +49,22 @@ const SendNotif: React.FC = () => {
-
-

- Send a Notification to

-

{formData.last_name}, {formData.first_name}

+
+

+ Send a Notification to{" "} +

+

+ {formData.last_name}, {formData.first_name}{" "} +

-
- + { />
- + + required>
diff --git a/frontend/src/types/datatypes.ts b/frontend/src/types/datatypes.ts index 933b5ef8..774e9b92 100644 --- a/frontend/src/types/datatypes.ts +++ b/frontend/src/types/datatypes.ts @@ -91,6 +91,7 @@ export interface UserType { export interface UserNotification { id?: string; driver_id?: string; + title?: string; message?: string; sender?: "Central Philippine School"; date_sent?: string; diff --git a/frontend/src/types/error.types.ts b/frontend/src/types/response.types.ts similarity index 52% rename from frontend/src/types/error.types.ts rename to frontend/src/types/response.types.ts index d5a50dc8..4a8f3f42 100644 --- a/frontend/src/types/error.types.ts +++ b/frontend/src/types/response.types.ts @@ -1,4 +1,4 @@ -export interface BackendError { +export interface BackendMessage { title: string; message: string; } diff --git a/frontend/src/utils/fetch.tsx b/frontend/src/utils/fetch.tsx index b6985d77..dee1b58e 100644 --- a/frontend/src/utils/fetch.tsx +++ b/frontend/src/utils/fetch.tsx @@ -1,5 +1,5 @@ import { NavigateFunction } from "react-router-dom"; -import { BackendError } from "../types/error.types"; +import { BackendMessage } from "../types/response.types"; import { User } from "../types/user.types"; export const normalFetch = async ( @@ -58,7 +58,7 @@ export const fetchWithAuth = async ( ); if (!newResponse.ok) { - const backendError: BackendError = await newResponse.json(); + const backendError: BackendMessage = await newResponse.json(); navigate("/unauthorized"); throw new Error(backendError.title + ": " + backendError.message); } diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index c241f5d6..772b9f65 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -12,7 +12,9 @@ export default { "2xl": "1536px", }, fontSize: { + "2xxs": ["0.5rem", "0.8rem"], xxs: ["0.5rem", "0.75rem"], + xxxs: ["0.4rem", "0.65rem"], }, colors: { textgreen: "#86C232",