diff --git a/backend/src/routes/cars.ts b/backend/src/routes/cars.ts index 33ff974c..44ce09b3 100644 --- a/backend/src/routes/cars.ts +++ b/backend/src/routes/cars.ts @@ -26,10 +26,7 @@ router.post("/check-license", async (req: Request, res: Response) => { return; } - res.status(200).json({ - title: "License Number Found", - message: "Driver with this license number exists.", - }); + res.status(200).json(driverFound); } catch (error) { console.log(error); res.sendStatus(500); diff --git a/frontend/src/components/AddCar.tsx b/frontend/src/components/AddCar.tsx new file mode 100644 index 00000000..e624aaaa --- /dev/null +++ b/frontend/src/components/AddCar.tsx @@ -0,0 +1,189 @@ +import React, { useState } from "react"; +import { Car } from "../types/datatypes"; +import useAddCar from "../hooks/car-hooks/useAddCar"; + +const AddCar = ({ + driverId, + licenseNumber, + setVehicleModalActive, +}: { + driverId: string; + licenseNumber: string; + setVehicleModalActive: React.Dispatch>; +}) => { + const { postCar } = useAddCar(); + + const [formData, setFormData] = useState({ + driver_id: driverId, + brand: "", + car_model: "", + color: "", + license_number: licenseNumber, + }); + + const [currentStep, setCurrentStep] = useState(1); + + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const handleSubmit = async () => { + await postCar(formData); + setVehicleModalActive(false); + }; + + const handleCancelButton = () => { + setVehicleModalActive(false); + }; + + const handleNextClick = async () => { + setCurrentStep(currentStep + 1); + }; + + const handleBackClick = () => { + setCurrentStep(currentStep - 1); + }; + + return ( +
+

Adding a Car

+ {currentStep === 1 && ( + <> +

Enter car details.

+
+
+
+

+ License Plate +

+ +
+
+ +
+
+

Brand

+ +
+
+

Model

+ +
+
+

Color

+ +
+
+
+ + )} + + {currentStep === 2 && ( + <> +

Confirm car details.

+
+
+
+

+ License Plate +

+

+ {formData.license_plate} +

+
+
+ +
+
+

Brand

+

+ {formData.brand} +

+
+
+

Model

+

+ {formData.car_model} +

+
+
+

Color

+

+ {formData.color} +

+
+
+
+ + )} + +
+ {currentStep === 1 && ( + <> + + + + + )} + {currentStep === 2 && ( + <> + + + + + )} +
+
+ ); +}; + +export default AddCar; diff --git a/frontend/src/components/AddCarButton.tsx b/frontend/src/components/AddCarButton.tsx index 39593202..44f6a7fd 100644 --- a/frontend/src/components/AddCarButton.tsx +++ b/frontend/src/components/AddCarButton.tsx @@ -1,5 +1,5 @@ import React from "react"; -import AddCar from "../pages/AddCar"; +import AddCar from "./AddCar"; import { DriverWithVandC } from "../types/datatypes"; const AddCarButton = ({ @@ -13,22 +13,22 @@ const AddCarButton = ({ vehicleModalActive: boolean; setVehicleModalActive: React.Dispatch>; }) => { - const handleAddVehicle = () => { + const handleAddVehiclePressed = () => { setVehicleModalActive(true); }; return ( <> {activeSection === "vehicle" && ( )} {vehicleModalActive && ( )} diff --git a/frontend/src/components/AddViolationButton.tsx b/frontend/src/components/AddViolationButton.tsx new file mode 100644 index 00000000..fa3f592f --- /dev/null +++ b/frontend/src/components/AddViolationButton.tsx @@ -0,0 +1,39 @@ +import React from "react"; +import { DriverWithVandC } from "../types/datatypes"; +import AddViolation from "./AddViolationComponent"; + +const AddViolationButton = ({ + activeSection, + driver, + violationModalActive, + setViolationModalActive, +}: { + activeSection: string; + driver: DriverWithVandC; + violationModalActive: boolean; + setViolationModalActive: React.Dispatch>; +}) => { + const handleAddViolationPressed = () => { + setViolationModalActive(true); + }; + + return ( + <> + {activeSection === "violation" && ( + + )} + {violationModalActive && ( + + )} + + ); +}; + +export default AddViolationButton; diff --git a/frontend/src/components/AddViolationComponent.tsx b/frontend/src/components/AddViolationComponent.tsx new file mode 100644 index 00000000..cddcfb3c --- /dev/null +++ b/frontend/src/components/AddViolationComponent.tsx @@ -0,0 +1,185 @@ +import { useState } from "react"; +import { Violation } from "../types/datatypes"; + +const AddViolationComponent = ({ + driverId, + setViolationModalActive, +}: { + driverId: string; + setViolationModalActive: React.Dispatch>; +}) => { + const [currentStep, setCurrentStep] = useState(1); + const [formData, setFormData] = useState({ + driver_id: driverId, + // place the necessary inputs needed + }); + + console.log(formData); // REMOVE THIS WHEN ALL IS DONE + + const handleSubmit = () => { + // Place + setViolationModalActive(false); + }; + + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const handleCancelButton = () => { + setViolationModalActive(false); + }; + + const handleNextClick = () => { + setCurrentStep(currentStep + 1); + }; + + const handleBackClick = () => { + setCurrentStep(currentStep - 1); + }; + + // EDIT THIS TO MAKE IT FOR VIOLATION + return ( +
+

+ EDIT THIS FOR ADDING VIOLATION +

+ {currentStep === 1 && ( + <> +

Enter car details.

+
+
+
+

+ License Plate +

+ +
+
+ +
+
+

Brand

+ +
+
+

Model

+ +
+
+

Color

+ +
+
+
+ + )} + + {currentStep === 2 && ( + <> +

Confirm car details.

+
+
+
+

+ License Plate +

+

+ {/* {formData.license_plate} */} +

+
+
+ +
+
+

Brand

+

+ {/* {formData.brand} */} +

+
+
+

Model

+

+ {/* {formData.car_model} */} +

+
+
+

Color

+

+ {/* {formData.color} */} +

+
+
+
+ + )} + +
+ {currentStep === 1 && ( + <> + + + + + )} + {currentStep === 2 && ( + <> + + + + + )} +
+
+ ); +}; + +export default AddViolationComponent; diff --git a/frontend/src/components/ProfileComponent/DriverProfileComp.tsx b/frontend/src/components/ProfileComponent/DriverProfileComp.tsx deleted file mode 100644 index f5bb05b0..00000000 --- a/frontend/src/components/ProfileComponent/DriverProfileComp.tsx +++ /dev/null @@ -1,91 +0,0 @@ - -const DriverProfileComponent = () => { - return ( -
-
-
-
-
-
-

Last Name

-

- Alcorin -

-
-
-

First Name

-

- Shawn Patrick -

-
-
-

Middle Name

-

- Surilla -

-
-
- -
-
-

Sex

-

- Female -

-
-
-

- Date of Birth -

-

- 02/29/2004 -

-
-
-

Driver Type

-

- Student -

-
-
- -
-
-
-

Email

-

- shawnpatrick.alcorin-23@cpu.edu.ph -

-
-
- -
-
-

- License Number -

-

- NO3-12-123456 -

-
-
-

- License Expiration Date -

-

- 03/10/2026 -

-
-
-
-
-
-
-
- ); -}; - -export default DriverProfileComponent; diff --git a/frontend/src/components/ProfileComponent/DriverVehicleComp.tsx b/frontend/src/components/ProfileComponent/DriverVehicleComp.tsx deleted file mode 100644 index 11dddb92..00000000 --- a/frontend/src/components/ProfileComponent/DriverVehicleComp.tsx +++ /dev/null @@ -1,103 +0,0 @@ -const DriverVehicleComponent = () => { - return ( -
-
-
    -
    -
    -
    -

    - Plate Number -

    -

    - 123-KVA -

    -
    -
    -

    - Car Registration Expiration Date -

    -

    - November 24, 2024 -

    -
    -
    - -
    -
    -

    Car Model

    -

    - 2022 Mitsubishi Montero Sport -

    -
    -
    -
    -
-
    -
    -
    -
    -

    - Plate Number -

    -

    - 349-KIW -

    -
    -
    -

    - Car Registration Expiration Date -

    -

    - July 13, 2044 -

    -
    -
    - -
    -
    -

    Car Model

    -

    - 2019 Honda Civic -

    -
    -
    -
    -
-
    -
    -
    -
    -

    - Plate Number -

    -

    - 123-KVA -

    -
    -
    -

    - Car Registration Expiration Date -

    -

    - November 24, 2024 -

    -
    -
    - -
    -
    -

    Car Model

    -

    - 2022 Mitsubishi Montero Sport -

    -
    -
    -
    -
-
-
- ); -}; - -export default DriverVehicleComponent; diff --git a/frontend/src/components/ProfileComponent/DriverViolationComp.tsx b/frontend/src/components/ProfileComponent/DriverViolationComp.tsx deleted file mode 100644 index c8cbeced..00000000 --- a/frontend/src/components/ProfileComponent/DriverViolationComp.tsx +++ /dev/null @@ -1,113 +0,0 @@ - -const DriverViolationComponent = () => { - return ( -
-
-
    -
    -
    -
    -

    Violation

    -

    - Expired Registration -

    -
    -
    -

    - Date of Violation -

    -

    - November 24, 2024 -

    -
    -
    -
    -
    -

    Description

    -

    - Operating with expired vehicle registration inside the campus. -

    -
    -
    -

    Status

    -

    - Paid -

    -
    -
    -
    -
-
    -
    -
    -
    -

    Violation

    -

    - Expired Registration -

    -
    -
    -

    - Date of Violation -

    -

    - November 24, 2024 -

    -
    -
    -
    -
    -

    Description

    -

    - Operating with expired vehicle registration inside the campus. -

    -
    -
    -

    Status

    -

    - Paid -

    -
    -
    -
    -
-
    -
    -
    -
    -

    Violation

    -

    - Expired Registration -

    -
    -
    -

    - Date of Violation -

    -

    - November 24, 2024 -

    -
    -
    -
    -
    -

    Description

    -

    - Operating with expired vehicle registration inside the campus. -

    -
    -
    -

    Status

    -

    - Paid -

    -
    -
    -
    -
-
-
- ); -}; - -export default DriverViolationComponent; diff --git a/frontend/src/hooks/car-hooks/useCheckLicenseNumber.ts b/frontend/src/hooks/car-hooks/useCheckLicenseNumber.ts index 202dd002..63cc4023 100644 --- a/frontend/src/hooks/car-hooks/useCheckLicenseNumber.ts +++ b/frontend/src/hooks/car-hooks/useCheckLicenseNumber.ts @@ -3,17 +3,16 @@ import { toast } from "react-toastify"; import { BackendError } from "../../types/error.types"; import { fetchWithAuth } from "../../utils/fetch"; import useFetchWithAuthExports from "../context-hooks/useFetchWithAuthExports"; +import { DriverWithVandC } from "../../types/datatypes"; const useCheckLicenseNumber = () => { const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); const { auth, refresh, navigate } = useFetchWithAuthExports(); const checkLicenseNumber = async ( license_number: string - ): Promise => { + ): Promise => { setLoading(true); - setError(null); try { // Make sure license_number is URL-safe @@ -32,23 +31,22 @@ const useCheckLicenseNumber = () => { if (!response.ok) { const backendError: BackendError = await response.json(); toast.error(backendError.message); - return false; + return } - const notification = await response.json(); - toast.success(notification.message); + const driver = await response.json(); - return true; // Assuming the backend sends { exists: true/false } + return driver; } catch (error) { console.error("Error checking license number:", error); - setError("Failed to verify license number."); - return false; + toast.error("Failed to verify license number."); + return; } finally { setLoading(false); } }; - return { checkLicenseNumber, loading, error }; + return { checkLicenseNumber, loading }; }; export default useCheckLicenseNumber; diff --git a/frontend/src/hooks/driver-hooks/useEditDriver.ts b/frontend/src/hooks/driver-hooks/useEditDriver.ts index c0ea243e..95f9880c 100644 --- a/frontend/src/hooks/driver-hooks/useEditDriver.ts +++ b/frontend/src/hooks/driver-hooks/useEditDriver.ts @@ -5,19 +5,20 @@ import useFetchWithAuthExports from "../context-hooks/useFetchWithAuthExports"; import { Driver } from "../../types/datatypes"; import useLoading from "../context-hooks/useLoading"; import { LoadingContextType } from "../../types/loading.types"; +import { toast } from "react-toastify"; export const useEditDriver = () => { const [error, setError] = useState<{ title: string; message: string } | null>( null ); - const { setAppLoading } : LoadingContextType = useLoading() + const { setAppLoading }: LoadingContextType = useLoading(); const { navigate, refresh, auth } = useFetchWithAuthExports(); const editDriver = async ( id: string, updatedDriver: Driver ): Promise => { - setAppLoading!(true) + setAppLoading!(true); try { const response = await fetchWithAuth( navigate, @@ -44,14 +45,12 @@ export const useEditDriver = () => { console.log("Driver updated:", data.driver); setError(null); // Clear any previous errors return true; - } catch (err: any) { - console.error("Error updating driver:", err); - setError({ - message: err.message || "Failed to connect to the server", - } as BackendError); + } catch (err) { + alert(err); + toast.error("Unexpected error has occurred."); return false; } finally { - setAppLoading!(false) + setAppLoading!(false); } }; diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 044c60ba..e20825a4 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -13,10 +13,8 @@ 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 DriverProfile from "./pages/DriverProfileSection.tsx"; import RegisterDriver from "./pages/RegisterDriver.tsx"; import AddDriver from "./pages/AddDriver.tsx"; -import AddViolation from "./pages/AddViolation.tsx"; import { AuthProvider } from "./context/AuthContext.tsx"; import UnauthorizedPage from "./pages/UnauthorizedPage.tsx"; import HomepageDriver from "./components/NotificationsList.tsx"; @@ -32,6 +30,7 @@ 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 = () => { @@ -45,27 +44,67 @@ const Main = () => { {/* PUBLIC ROUTES */} - } /> - } /> + + } + /> + } + /> - } /> + } + /> - } /> + } + /> }> {/* FOR ALL LOGGED IN */} - } /> - } /> + } + /> + } + /> {/* USER ROUTES */} }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> {/* ADMIN ROUTES */} @@ -88,7 +127,7 @@ const Main = () => { /> } + element={} /> { const navigate = useNavigate(); - const { checkLicenseNumber, loading, error } = useCheckLicenseNumber(); // using the hook + const { checkLicenseNumber, loading } = useCheckLicenseNumber(); // using the hook const [currentStep, setCurrentStep] = useState(1); const [licenseNumber, setLicenseNumber] = useState(""); - const [driverProfile, setDriverProfile] = useState(null); // Store the driver profile + const [driverProfile, setDriverProfile] = useState(); // Store the driver profile const handleCancelButton = () => { navigate("/encode"); @@ -18,16 +19,15 @@ const AddViolation = () => { const handleNextClick = async () => { try { - const driverExists = await checkLicenseNumber(licenseNumber); - if (driverExists) { + const driver = await checkLicenseNumber(licenseNumber); + console.log(driver); + if (driver) { + setDriverProfile(driver); setCurrentStep(currentStep + 1); - - // Use the hook to get driver details with license number, and use - // useState "setDriverProfile" to set the driverProfile as the result - return; } } catch (error) { + alert(error); toast.error("Something went wrong!"); } }; @@ -92,7 +92,7 @@ const AddViolation = () => { Last Name

- {driverProfile.lastName} + {driverProfile.last_name}

@@ -101,7 +101,7 @@ const AddViolation = () => { First Name

- {driverProfile.firstName} + {driverProfile.first_name}

@@ -119,7 +119,7 @@ const AddViolation = () => { Date of Birth

- {driverProfile.dateOfBirth} + {driverProfile.date_of_birth}

@@ -127,7 +127,7 @@ const AddViolation = () => { Driver Type

- {driverProfile.driverType} + {driverProfile.driver_type}

@@ -138,7 +138,7 @@ const AddViolation = () => { License Number

- {driverProfile.licenseNumber} + {driverProfile.license_number}

@@ -146,7 +146,7 @@ const AddViolation = () => { License Expiration Date

- {driverProfile.expirationDate} + {driverProfile.license_expiration_date}

@@ -162,8 +162,7 @@ const AddViolation = () => { @@ -173,8 +172,7 @@ const AddViolation = () => { type="button" className="w-32 bg-buttongreen font-syke-medium text-white py-2 hover:bg-[#33471a] font-syke-regular transition-colors rounded-sm" onClick={handleNextClick} - disabled={loading} - > + disabled={loading}> {loading ? "Searching..." : "Search"} @@ -187,8 +185,7 @@ const AddViolation = () => { @@ -197,8 +194,7 @@ const AddViolation = () => { diff --git a/frontend/src/pages/DriverProfileSection.tsx b/frontend/src/pages/DriverProfileSection.tsx deleted file mode 100644 index 2ae0015a..00000000 --- a/frontend/src/pages/DriverProfileSection.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import Header from "../components/Header"; -import DriverProfileComponents from "../components/ProfileComponent/DriverProfileComp"; -import DriverVehicleComponent from "../components/ProfileComponent/DriverVehicleComp"; -import DriverViolationComponent from "../components/ProfileComponent/DriverViolationComp"; - -import { useState } from "react"; -const DriverProfile = () => { - const [activeSection, SetActiveSection] = useState("profile"); - - return ( -
-
-
-
- -

- My Gateway Account -

- -
- - - {activeSection === "profile" && } - - {activeSection === "vehicle" && } - - {activeSection === "violation" && } -
-
- ); -}; - -export default DriverProfile; diff --git a/frontend/src/pages/ViewProfile.tsx b/frontend/src/pages/ViewProfile.tsx index 5c0498b1..3093141a 100644 --- a/frontend/src/pages/ViewProfile.tsx +++ b/frontend/src/pages/ViewProfile.tsx @@ -10,6 +10,7 @@ import { AuthContextType } from "../types/user.types"; import useAuth from "../hooks/context-hooks/useAuth"; import Loading from "../components/Loading"; import AddCarButton from "../components/AddCarButton"; +import AddViolationButton from "../components/AddViolationButton"; const ViewProfile = () => { const { driverId } = useParams<{ driverId: string }>(); @@ -17,6 +18,8 @@ const ViewProfile = () => { const { loading, driver } = useGetDriver(driverId!); const { auth }: AuthContextType = useAuth(); const [vehicleModalActive, setVehicleModalActive] = useState(false); + const [violationModalActive, setViolationModalActive] = + useState(false); if (loading) { return ; @@ -78,6 +81,12 @@ const ViewProfile = () => { vehicleModalActive={vehicleModalActive} setVehicleModalActive={setVehicleModalActive} /> + );