diff --git a/client/pages/StaffLogin.tsx b/client/pages/StaffLogin.tsx new file mode 100644 index 00000000..d0a34144 --- /dev/null +++ b/client/pages/StaffLogin.tsx @@ -0,0 +1,186 @@ +import { useEffect, useState } from "react"; +import { useNavigate, useLocation } from "react-router-dom"; +import { useAuth } from "@/contexts/AuthContext"; +import { useAethexToast } from "@/hooks/use-aethex-toast"; +import Layout from "@/components/Layout"; +import SEO from "@/components/SEO"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import LoadingScreen from "@/components/LoadingScreen"; +import { LogIn, Lock, Users } from "lucide-react"; + +const GoogleIcon = () => ( + + + + + + +); + +export default function StaffLogin() { + const [isLoading, setIsLoading] = useState(false); + const [errorFromUrl, setErrorFromUrl] = useState(null); + const navigate = useNavigate(); + const location = useLocation(); + const { signInWithOAuth, user, loading, profileComplete } = useAuth(); + const { error: toastError, info: toastInfo } = useAethexToast(); + + // Check for error messages from URL (e.g., from OAuth callbacks) + useEffect(() => { + const params = new URLSearchParams(location.search); + const errorType = params.get("error"); + const errorMessage = params.get("message"); + + if (errorType && errorMessage) { + setErrorFromUrl(decodeURIComponent(errorMessage)); + if (errorType === "domain_not_allowed") { + toastError({ + title: "Access Denied", + description: errorMessage, + }); + } + } + }, [location.search, toastError]); + + // Redirect if already authenticated + useEffect(() => { + if (!loading && user) { + const params = new URLSearchParams(location.search); + const next = params.get("next"); + const safeNext = next && next.startsWith("/staff") ? next : null; + navigate(safeNext || "/staff/dashboard", { replace: true }); + } + }, [user, loading, navigate, location.search]); + + const handleGoogleSignIn = async () => { + setIsLoading(true); + try { + await signInWithOAuth("google"); + } catch (error: any) { + console.error("Google sign-in error:", error); + toastError({ + title: "Sign-in failed", + description: + error?.message || "Failed to sign in with Google. Please try again.", + }); + } finally { + setIsLoading(false); + } + }; + + if (loading) { + return ; + } + + return ( + + + + + + + + + + + + + + + + + + Staff Portal + + AeThex employees and authorized contractors only + + + + + {errorFromUrl && ( + + Access Denied + {errorFromUrl} + + )} + + + + Sign in with your @aethex.dev Google Workspace account + + + + + {isLoading ? "Signing in..." : "Sign in with Google"} + + + + + + + + + + For team members only + + + + + + + + Full access to internal tools and dashboards + + + + Secured with Google Workspace authentication + + + + + + Public login available at{" "} + + aethex.dev/login + + + + + + + + + ); +}
+ Sign in with your @aethex.dev Google Workspace account +
+ Public login available at{" "} + + aethex.dev/login + +