Create Staff Login page with Google OAuth validation

cgen-78509c2a6b2244d699c766ee6f0aeeba
This commit is contained in:
Builder.io 2025-11-11 17:18:16 +00:00
parent 30c2c556a7
commit dd24c2bbe9

138
client/pages/StaffLogin.tsx Normal file
View file

@ -0,0 +1,138 @@
import { useState, useEffect } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import Layout from "@/components/Layout";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { useAuth } from "@/contexts/AuthContext";
import { useAethexToast } from "@/hooks/use-aethex-toast";
import LoadingScreen from "@/components/LoadingScreen";
import { Mail, AlertCircle, Loader2 } from "lucide-react";
export default function StaffLogin() {
const navigate = useNavigate();
const location = useLocation();
const { signInWithOAuth, user, loading, profile } = useAuth();
const { error: toastError, info: toastInfo } = useAethexToast();
const [isSigningIn, setIsSigningIn] = useState(false);
const [error, setError] = useState<string | null>(null);
// Redirect if already authenticated and has @aethex.dev email
useEffect(() => {
if (!loading && user && profile) {
const email = user.email || profile.email || "";
if (email.endsWith("@aethex.dev")) {
toastInfo({
title: "Already logged in",
description: "Redirecting to staff dashboard...",
});
navigate("/staff/dashboard", { replace: true });
} else {
setError("Only @aethex.dev email addresses are allowed");
}
}
}, [user, profile, loading, navigate, toastInfo]);
const handleGoogleSignIn = async () => {
setIsSigningIn(true);
setError(null);
try {
await signInWithOAuth("google");
// Note: Redirect will happen in the useEffect above after auth completes
} catch (err: any) {
const errorMsg =
err?.message || "Failed to sign in with Google. Please try again.";
setError(errorMsg);
toastError({
title: "Sign in failed",
description: errorMsg,
});
setIsSigningIn(false);
}
};
if (loading) {
return (
<LoadingScreen
message="Authenticating..."
showProgress={true}
duration={3000}
/>
);
}
return (
<Layout hideNav>
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-950 via-purple-900/20 to-slate-950 px-4">
<Card className="w-full max-w-md border-purple-500/20 bg-slate-900/80 backdrop-blur">
<CardHeader className="space-y-4 text-center">
<div className="flex justify-center">
<div className="w-16 h-16 rounded-full bg-gradient-to-br from-purple-500 to-purple-600 flex items-center justify-center">
<Shield className="w-8 h-8 text-white" />
</div>
</div>
<CardTitle className="text-2xl font-bold text-white">
Staff Portal
</CardTitle>
<p className="text-sm text-gray-300">
Internal operations and management dashboard for AeThex staff
</p>
</CardHeader>
<CardContent className="space-y-6">
{error && (
<Alert className="border-red-500/50 bg-red-500/10">
<AlertCircle className="h-4 w-4 text-red-500" />
<AlertDescription className="text-red-300 ml-2">
{error}
</AlertDescription>
</Alert>
)}
<div className="space-y-3">
<p className="text-sm text-gray-400 text-center">
Only staff members with @aethex.dev email addresses can access
this portal
</p>
<Button
onClick={handleGoogleSignIn}
disabled={isSigningIn}
className="w-full h-11 bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white font-medium flex items-center justify-center gap-2"
>
{isSigningIn ? (
<>
<Loader2 className="w-4 h-4 animate-spin" />
Signing in...
</>
) : (
<>
<Mail className="w-4 h-4" />
Sign in with Google
</>
)}
</Button>
</div>
<div className="pt-4 border-t border-purple-500/20">
<p className="text-xs text-gray-500 text-center">
This portal is restricted to authorized AeThex staff members
</p>
</div>
</CardContent>
</Card>
</div>
</Layout>
);
}
const Shield = ({ className }: { className: string }) => (
<svg
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z" />
</svg>
);