From 7a1da8c0d477b9f6cd736675334126484b10b7a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Salazar?=
<73718835+joshrs23@users.noreply.github.com>
Date: Fri, 28 Nov 2025 13:59:29 -0500
Subject: [PATCH] auth working in webpage
---
.../src/components/auth/ProtectedRoute.jsx | 25 +
.../src/components/auth/PublicRoute.jsx | 25 +
frontend-web/src/hooks/useAuth.js | 19 +
frontend-web/src/pages/Login.jsx | 86 +++
frontend-web/src/pages/Register.jsx | 128 ++++
frontend-web/src/pages/index.jsx | 706 ++++++------------
6 files changed, 531 insertions(+), 458 deletions(-)
create mode 100644 frontend-web/src/components/auth/ProtectedRoute.jsx
create mode 100644 frontend-web/src/components/auth/PublicRoute.jsx
create mode 100644 frontend-web/src/hooks/useAuth.js
create mode 100644 frontend-web/src/pages/Login.jsx
create mode 100644 frontend-web/src/pages/Register.jsx
diff --git a/frontend-web/src/components/auth/ProtectedRoute.jsx b/frontend-web/src/components/auth/ProtectedRoute.jsx
new file mode 100644
index 00000000..22384a45
--- /dev/null
+++ b/frontend-web/src/components/auth/ProtectedRoute.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { Navigate } from 'react-router-dom';
+import { useAuth } from '@/hooks/useAuth';
+import { Loader2 } from 'lucide-react';
+
+export default function ProtectedRoute({ children }) {
+ const { user, loading } = useAuth();
+
+ if (loading) {
+ return (
+
+ );
+ }
+
+ if (!user) {
+ return ;
+ }
+
+ return children;
+}
\ No newline at end of file
diff --git a/frontend-web/src/components/auth/PublicRoute.jsx b/frontend-web/src/components/auth/PublicRoute.jsx
new file mode 100644
index 00000000..55d4d0d8
--- /dev/null
+++ b/frontend-web/src/components/auth/PublicRoute.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { Navigate } from 'react-router-dom';
+import { useAuth } from '@/hooks/useAuth';
+import { Loader2 } from 'lucide-react';
+
+export default function PublicRoute({ children }) {
+ const { user, loading } = useAuth();
+
+ if (loading) {
+ return (
+
+ );
+ }
+
+ if (user) {
+ return ;
+ }
+
+ return children;
+}
\ No newline at end of file
diff --git a/frontend-web/src/hooks/useAuth.js b/frontend-web/src/hooks/useAuth.js
new file mode 100644
index 00000000..51d3b33e
--- /dev/null
+++ b/frontend-web/src/hooks/useAuth.js
@@ -0,0 +1,19 @@
+import { useState, useEffect } from 'react';
+import { onAuthStateChanged } from 'firebase/auth';
+import { auth } from '@/firebase';
+
+export function useAuth() {
+ const [user, setUser] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ const unsubscribe = onAuthStateChanged(auth, (user) => {
+ setUser(user);
+ setLoading(false);
+ });
+
+ return () => unsubscribe();
+ }, []);
+
+ return { user, loading };
+}
\ No newline at end of file
diff --git a/frontend-web/src/pages/Login.jsx b/frontend-web/src/pages/Login.jsx
new file mode 100644
index 00000000..c5263c9f
--- /dev/null
+++ b/frontend-web/src/pages/Login.jsx
@@ -0,0 +1,86 @@
+import React, { useState } from "react";
+import { useNavigate, Link } from "react-router-dom";
+import { signInWithEmailAndPassword } from "firebase/auth";
+import { auth } from "@/firebase";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { Loader2 } from "lucide-react";
+
+export default function Login() {
+ const navigate = useNavigate();
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const [error, setError] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const handleLogin = async (e) => {
+ e.preventDefault();
+ setError(null);
+
+ if (!email || !password) {
+ setError("Email and password are required.");
+ return;
+ }
+
+ setLoading(true);
+ try {
+ await signInWithEmailAndPassword(auth, email, password);
+ navigate("/");
+ } catch (error) {
+ setError("Invalid credentials. Please try again.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+ Login
+ Enter your credentials to access your account.
+
+
+
+
+
+
+
+ Don't have an account?{" "}
+
+ Register
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/frontend-web/src/pages/Register.jsx b/frontend-web/src/pages/Register.jsx
new file mode 100644
index 00000000..7e1931e5
--- /dev/null
+++ b/frontend-web/src/pages/Register.jsx
@@ -0,0 +1,128 @@
+import React, { useState } from "react";
+import { useNavigate, Link } from "react-router-dom";
+import { createUserWithEmailAndPassword } from "firebase/auth";
+import { auth } from "@/firebase";
+import { Button } from "@/components/ui/button";
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { Loader2 } from "lucide-react";
+
+export default function Register() {
+ const navigate = useNavigate();
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const [error, setError] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const validatePassword = (password) => {
+ if (password.length < 6) {
+ return "Password must be at least 6 characters long.";
+ }
+ return null;
+ };
+
+ const validateEmail = (email) => {
+ const re =
+ /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+ if (!re.test(String(email).toLowerCase())) {
+ return "Invalid email address.";
+ }
+ return null;
+ };
+
+ const handleRegister = async (e) => {
+ e.preventDefault();
+ setError(null);
+
+ if (!email || !password) {
+ setError("Email and password are required.");
+ return;
+ }
+
+ const emailError = validateEmail(email);
+ if (emailError) {
+ setError(emailError);
+ return;
+ }
+
+ const passwordError = validatePassword(password);
+ if (passwordError) {
+ setError(passwordError);
+ return;
+ }
+
+ setLoading(true);
+ try {
+ await createUserWithEmailAndPassword(auth, email, password);
+ navigate("/");
+ } catch (error) {
+ setError(error.message || "Something went wrong. Please try again.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+ Register
+ Create a new account.
+
+
+
+
+
+
+
+
+
+
+ Already have an account?{" "}
+
+ Login
+
+
+
+
+
+ );
+}
diff --git a/frontend-web/src/pages/index.jsx b/frontend-web/src/pages/index.jsx
index c3d5213d..6caeef9f 100644
--- a/frontend-web/src/pages/index.jsx
+++ b/frontend-web/src/pages/index.jsx
@@ -1,477 +1,267 @@
-import Layout from "./Layout.jsx";
-
-import Dashboard from "./Dashboard";
-
-import StaffDirectory from "./StaffDirectory";
-
-import AddStaff from "./AddStaff";
-
-import EditStaff from "./EditStaff";
-
-import Events from "./Events";
-
-import CreateEvent from "./CreateEvent";
-
-import EditEvent from "./EditEvent";
-
-import EventDetail from "./EventDetail";
-
-import Business from "./Business";
-
-import Invoices from "./Invoices";
-
-import Payroll from "./Payroll";
-
-import Certification from "./Certification";
-
-import Support from "./Support";
-
-import Reports from "./Reports";
-
-import Settings from "./Settings";
-
-import ActivityLog from "./ActivityLog";
-
-import AddBusiness from "./AddBusiness";
-
-import EditBusiness from "./EditBusiness";
-
-import ProcurementDashboard from "./ProcurementDashboard";
-
-import OperatorDashboard from "./OperatorDashboard";
-
-import VendorDashboard from "./VendorDashboard";
-
-import WorkforceDashboard from "./WorkforceDashboard";
-
-import Messages from "./Messages";
-
-import ClientDashboard from "./ClientDashboard";
-
-import Onboarding from "./Onboarding";
-
-import ClientOrders from "./ClientOrders";
-
-import ClientInvoices from "./ClientInvoices";
-
-import VendorOrders from "./VendorOrders";
-
-import VendorStaff from "./VendorStaff";
-
-import VendorInvoices from "./VendorInvoices";
-
-import VendorPerformance from "./VendorPerformance";
-
-import WorkforceShifts from "./WorkforceShifts";
-
-import WorkforceEarnings from "./WorkforceEarnings";
-
-import WorkforceProfile from "./WorkforceProfile";
-
-import UserManagement from "./UserManagement";
-
-import Home from "./Home";
-
-import VendorRateCard from "./VendorRateCard";
-
-import Permissions from "./Permissions";
-
-import WorkforceCompliance from "./WorkforceCompliance";
-
-import Teams from "./Teams";
-
-import CreateTeam from "./CreateTeam";
-
-import TeamDetails from "./TeamDetails";
-
-import VendorManagement from "./VendorManagement";
-
-import PartnerManagement from "./PartnerManagement";
-
-import EnterpriseManagement from "./EnterpriseManagement";
-
-import VendorOnboarding from "./VendorOnboarding";
-
-import SectorManagement from "./SectorManagement";
-
-import AddEnterprise from "./AddEnterprise";
-
-import AddSector from "./AddSector";
-
-import AddPartner from "./AddPartner";
-
-import EditVendor from "./EditVendor";
-
-import SmartVendorOnboarding from "./SmartVendorOnboarding";
-
-import InviteVendor from "./InviteVendor";
-
-import VendorCompliance from "./VendorCompliance";
-
-import EditPartner from "./EditPartner";
-
-import EditSector from "./EditSector";
-
-import EditEnterprise from "./EditEnterprise";
-
-import VendorRates from "./VendorRates";
-
-import VendorDocumentReview from "./VendorDocumentReview";
-
-import VendorMarketplace from "./VendorMarketplace";
-
-import RapidOrder from "./RapidOrder";
-
-import SmartScheduler from "./SmartScheduler";
-
-import StaffOnboarding from "./StaffOnboarding";
-
-import NotificationSettings from "./NotificationSettings";
-
-import TaskBoard from "./TaskBoard";
-
-import InvoiceDetail from "./InvoiceDetail";
-
-import InvoiceEditor from "./InvoiceEditor";
-
-//import api-docs-raw from "./api-docs-raw";
-
-import Tutorials from "./Tutorials";
-
-import Schedule from "./Schedule";
-
-import StaffAvailability from "./StaffAvailability";
-
-import WorkerShiftProposals from "./WorkerShiftProposals";
-
import { BrowserRouter as Router, Route, Routes, useLocation } from 'react-router-dom';
+// Auth components
+import ProtectedRoute from '@/components/auth/ProtectedRoute';
+import PublicRoute from '@/components/auth/PublicRoute';
+
+// Layout and pages
+import Layout from "./Layout.jsx";
+import Home from "./Home";
+import Login from "./Login";
+import Register from "./Register";
+import Dashboard from "./Dashboard";
+import StaffDirectory from "./StaffDirectory";
+import AddStaff from "./AddStaff";
+import EditStaff from "./EditStaff";
+import Events from "./Events";
+import CreateEvent from "./CreateEvent";
+import EditEvent from "./EditEvent";
+import EventDetail from "./EventDetail";
+import Business from "./Business";
+import Invoices from "./Invoices";
+import Payroll from "./Payroll";
+import Certification from "./Certification";
+import Support from "./Support";
+import Reports from "./Reports";
+import Settings from "./Settings";
+import ActivityLog from "./ActivityLog";
+import AddBusiness from "./AddBusiness";
+import EditBusiness from "./EditBusiness";
+import ProcurementDashboard from "./ProcurementDashboard";
+import OperatorDashboard from "./OperatorDashboard";
+import VendorDashboard from "./VendorDashboard";
+import WorkforceDashboard from "./WorkforceDashboard";
+import Messages from "./Messages";
+import ClientDashboard from "./ClientDashboard";
+import Onboarding from "./Onboarding";
+import ClientOrders from "./ClientOrders";
+import ClientInvoices from "./ClientInvoices";
+import VendorOrders from "./VendorOrders";
+import VendorStaff from "./VendorStaff";
+import VendorInvoices from "./VendorInvoices";
+import VendorPerformance from "./VendorPerformance";
+import WorkforceShifts from "./WorkforceShifts";
+import WorkforceEarnings from "./WorkforceEarnings";
+import WorkforceProfile from "./WorkforceProfile";
+import UserManagement from "./UserManagement";
+import VendorRateCard from "./VendorRateCard";
+import Permissions from "./Permissions";
+import WorkforceCompliance from "./WorkforceCompliance";
+import Teams from "./Teams";
+import CreateTeam from "./CreateTeam";
+import TeamDetails from "./TeamDetails";
+import VendorManagement from "./VendorManagement";
+import PartnerManagement from "./PartnerManagement";
+import EnterpriseManagement from "./EnterpriseManagement";
+import VendorOnboarding from "./VendorOnboarding";
+import SectorManagement from "./SectorManagement";
+import AddEnterprise from "./AddEnterprise";
+import AddSector from "./AddSector";
+import AddPartner from "./AddPartner";
+import EditVendor from "./EditVendor";
+import SmartVendorOnboarding from "./SmartVendorOnboarding";
+import InviteVendor from "./InviteVendor";
+import VendorCompliance from "./VendorCompliance";
+import EditPartner from "./EditPartner";
+import EditSector from "./EditSector";
+import EditEnterprise from "./EditEnterprise";
+import VendorRates from "./VendorRates";
+import VendorDocumentReview from "./VendorDocumentReview";
+import VendorMarketplace from "./VendorMarketplace";
+import RapidOrder from "./RapidOrder";
+import SmartScheduler from "./SmartScheduler";
+import StaffOnboarding from "./StaffOnboarding";
+import NotificationSettings from "./NotificationSettings";
+import TaskBoard from "./TaskBoard";
+import InvoiceDetail from "./InvoiceDetail";
+import InvoiceEditor from "./InvoiceEditor";
+import Tutorials from "./Tutorials";
+import Schedule from "./Schedule";
+import StaffAvailability from "./StaffAvailability";
+import WorkerShiftProposals from "./WorkerShiftProposals";
+
const PAGES = {
-
- Dashboard: Dashboard,
-
- StaffDirectory: StaffDirectory,
-
- AddStaff: AddStaff,
-
- EditStaff: EditStaff,
-
- Events: Events,
-
- CreateEvent: CreateEvent,
-
- EditEvent: EditEvent,
-
- EventDetail: EventDetail,
-
- Business: Business,
-
- Invoices: Invoices,
-
- Payroll: Payroll,
-
- Certification: Certification,
-
- Support: Support,
-
- Reports: Reports,
-
- Settings: Settings,
-
- ActivityLog: ActivityLog,
-
- AddBusiness: AddBusiness,
-
- EditBusiness: EditBusiness,
-
- ProcurementDashboard: ProcurementDashboard,
-
- OperatorDashboard: OperatorDashboard,
-
- VendorDashboard: VendorDashboard,
-
- WorkforceDashboard: WorkforceDashboard,
-
- Messages: Messages,
-
- ClientDashboard: ClientDashboard,
-
- Onboarding: Onboarding,
-
- ClientOrders: ClientOrders,
-
- ClientInvoices: ClientInvoices,
-
- VendorOrders: VendorOrders,
-
- VendorStaff: VendorStaff,
-
- VendorInvoices: VendorInvoices,
-
- VendorPerformance: VendorPerformance,
-
- WorkforceShifts: WorkforceShifts,
-
- WorkforceEarnings: WorkforceEarnings,
-
- WorkforceProfile: WorkforceProfile,
-
- UserManagement: UserManagement,
-
- Home: Home,
-
- VendorRateCard: VendorRateCard,
-
- Permissions: Permissions,
-
- WorkforceCompliance: WorkforceCompliance,
-
- Teams: Teams,
-
- CreateTeam: CreateTeam,
-
- TeamDetails: TeamDetails,
-
- VendorManagement: VendorManagement,
-
- PartnerManagement: PartnerManagement,
-
- EnterpriseManagement: EnterpriseManagement,
-
- VendorOnboarding: VendorOnboarding,
-
- SectorManagement: SectorManagement,
-
- AddEnterprise: AddEnterprise,
-
- AddSector: AddSector,
-
- AddPartner: AddPartner,
-
- EditVendor: EditVendor,
-
- SmartVendorOnboarding: SmartVendorOnboarding,
-
- InviteVendor: InviteVendor,
-
- VendorCompliance: VendorCompliance,
-
- EditPartner: EditPartner,
-
- EditSector: EditSector,
-
- EditEnterprise: EditEnterprise,
-
- VendorRates: VendorRates,
-
- VendorDocumentReview: VendorDocumentReview,
-
- VendorMarketplace: VendorMarketplace,
-
- RapidOrder: RapidOrder,
-
- SmartScheduler: SmartScheduler,
-
- StaffOnboarding: StaffOnboarding,
-
- NotificationSettings: NotificationSettings,
-
- TaskBoard: TaskBoard,
-
- InvoiceDetail: InvoiceDetail,
-
- InvoiceEditor: InvoiceEditor,
-
- //api-docs-raw: api-docs-raw,
-
- Tutorials: Tutorials,
-
- Schedule: Schedule,
-
- StaffAvailability: StaffAvailability,
-
- WorkerShiftProposals: WorkerShiftProposals,
-
-}
+ Dashboard,
+ StaffDirectory,
+ AddStaff,
+ EditStaff,
+ Events,
+ CreateEvent,
+ EditEvent,
+ EventDetail,
+ Business,
+ Invoices,
+ Payroll,
+ Certification,
+ Support,
+ Reports,
+ Settings,
+ ActivityLog,
+ AddBusiness,
+ EditBusiness,
+ ProcurementDashboard,
+ OperatorDashboard,
+ VendorDashboard,
+ WorkforceDashboard,
+ Messages,
+ ClientDashboard,
+ Onboarding,
+ ClientOrders,
+ ClientInvoices,
+ VendorOrders,
+ VendorStaff,
+ VendorInvoices,
+ VendorPerformance,
+ WorkforceShifts,
+ WorkforceEarnings,
+ WorkforceProfile,
+ UserManagement,
+ Home,
+ VendorRateCard,
+ Permissions,
+ WorkforceCompliance,
+ Teams,
+ CreateTeam,
+ TeamDetails,
+ VendorManagement,
+ PartnerManagement,
+ EnterpriseManagement,
+ VendorOnboarding,
+ SectorManagement,
+ AddEnterprise,
+ AddSector,
+ AddPartner,
+ EditVendor,
+ SmartVendorOnboarding,
+ InviteVendor,
+ VendorCompliance,
+ EditPartner,
+ EditSector,
+ EditEnterprise,
+ VendorRates,
+ VendorDocumentReview,
+ VendorMarketplace,
+ RapidOrder,
+ SmartScheduler,
+ StaffOnboarding,
+ NotificationSettings,
+ TaskBoard,
+ InvoiceDetail,
+ InvoiceEditor,
+ Tutorials,
+ Schedule,
+ StaffAvailability,
+ WorkerShiftProposals,
+};
function _getCurrentPage(url) {
- if (url.endsWith('/')) {
- url = url.slice(0, -1);
- }
- let urlLastPart = url.split('/').pop();
- if (urlLastPart.includes('?')) {
- urlLastPart = urlLastPart.split('?')[0];
- }
-
- const pageName = Object.keys(PAGES).find(page => page.toLowerCase() === urlLastPart.toLowerCase());
- return pageName || Object.keys(PAGES)[0];
+ if (url.endsWith('/')) url = url.slice(0, -1);
+ let last = url.split('/').pop();
+ if (last.includes('?')) last = last.split('?')[0];
+ const pageName = Object.keys(PAGES).find(p => p.toLowerCase() === last.toLowerCase());
+ return pageName || 'Home'; // Default to Home
}
-// Create a wrapper component that uses useLocation inside the Router context
-function PagesContent() {
+
+function AppRoutes() {
const location = useLocation();
const currentPage = _getCurrentPage(location.pathname);
-
+
return (
-
-
-
- } />
-
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
-
-
+
+ {/* Public Routes */}
+ } />
+ } />
+
+ {/* Private Routes */}
+
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+
+ } />
+
);
}
export default function Pages() {
return (
-
+
);
}
\ No newline at end of file