NewsAnalyze / src /components /AuthModal.tsx
GeoStrat-CI
Deploy 5924376 to Hugging Face Space [skip ci]
2c0e275
Raw History Blame Contribute Delete
8.02 kB
import React, { useState } from "react";
import {
auth,
googleProvider,
signInWithPopup,
signInWithEmailAndPassword,
createUserWithEmailAndPassword,
} from "../config/firebase.js";
import { Lock, Mail, LogIn, UserPlus, AlertCircle, X } from "lucide-react";
import { useLanguage } from "../context/LanguageContext.js";
interface AuthModalProps {
isOpen: boolean;
onClose: () => void;
}
export const AuthModal: React.FC<AuthModalProps> = ({ isOpen, onClose }) => {
const { language, t, isRtl } = useLanguage();
const [mode, setMode] = useState<"login" | "register">("login");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
if (!isOpen) return null;
const handleGoogleSignIn = async () => {
setLoading(true);
setError("");
try {
await signInWithPopup(auth, googleProvider);
onClose();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : "Google Sign-In failed.";
setError(msg);
} finally {
setLoading(false);
}
};
const handleEmailSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!email || !password) {
setError(language === "ar" ? "يرجى إدخال البريد الإلكتروني وكلمة المرور." : "Please fill in both email and password.");
return;
}
setLoading(true);
setError("");
try {
if (mode === "login") {
await signInWithEmailAndPassword(auth, email, password);
} else {
await createUserWithEmailAndPassword(auth, email, password);
}
onClose();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : "Authentication failed.";
setError(msg);
} finally {
setLoading(false);
}
};
return (
<div className="fixed inset-0 bg-slate-950/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div className="bg-slate-900 border border-slate-800 rounded-xl p-6 max-w-md w-full shadow-2xl space-y-5 relative">
<button
onClick={onClose}
className={`absolute top-4 ${isRtl ? "left-4" : "right-4"} text-slate-400 hover:text-white p-1 rounded-lg bg-slate-800 hover:bg-slate-700 transition-colors cursor-pointer`}
>
<X className="w-4 h-4" />
</button>
<div className="text-center">
<div className="w-10 h-10 rounded-xl bg-cyan-500/10 border border-cyan-500/30 text-cyan-400 flex items-center justify-center mx-auto mb-2 font-bold font-mono text-base">
GS
</div>
<h2 className="text-lg font-bold text-white font-display">
{mode === "login" ? t.auth.signInTitle : (language === "ar" ? "إنشاء حساب جديد" : "Create Your Account")}
</h2>
<p className="text-xs text-slate-400 mt-1 font-sans">
{t.auth.signInSubtitle}
</p>
</div>
{error && (
<div className="p-3 bg-rose-950/50 border border-rose-800/80 rounded-lg text-rose-300 text-xs font-mono flex items-center gap-2">
<AlertCircle className="w-4 h-4 text-rose-400 shrink-0" />
<span className="truncate">{error}</span>
</div>
)}
{/* Google Registration & Sign In Button */}
<button
onClick={handleGoogleSignIn}
disabled={loading}
className="w-full py-2.5 px-4 bg-slate-800 hover:bg-slate-700 border border-slate-700 rounded-lg text-xs font-medium text-slate-200 transition-all flex items-center justify-center gap-2 shadow-sm font-sans cursor-pointer"
>
<svg className="w-4 h-4" viewBox="0 0 24 24">
<path
fill="#4285F4"
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
/>
<path
fill="#34A853"
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
/>
<path
fill="#FBBC05"
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.06H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.94l2.85-2.22.81-.63z"
/>
<path
fill="#EA4335"
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.06l3.66 2.84c.87-2.6 3.3-4.52 6.16-4.52z"
/>
</svg>
{t.auth.googleBtn}
</button>
<div className="flex items-center gap-3 text-[11px] font-mono text-slate-500 uppercase my-2">
<div className="flex-1 h-px bg-slate-800" />
<span>{language === "ar" ? "أو عبر البريد الإلكتروني" : "Or with Email"}</span>
<div className="flex-1 h-px bg-slate-800" />
</div>
{/* Email & Password Form */}
<form onSubmit={handleEmailSubmit} className="space-y-3">
<div>
<label className="text-[11px] font-mono text-slate-400 block mb-1">{t.auth.emailLabel}</label>
<div className="relative">
<Mail className={`w-4 h-4 text-slate-500 absolute ${isRtl ? "right-3" : "left-3"} top-2.5`} />
<input
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="analyst@sovereign-macro.org"
className={`w-full bg-slate-950 border border-slate-800 rounded-lg ${isRtl ? "pr-9 pl-3 text-right" : "pl-9 pr-3 text-left"} py-2 text-xs text-slate-200 focus:outline-none focus:border-cyan-500`}
/>
</div>
</div>
<div>
<label className="text-[11px] font-mono text-slate-400 block mb-1">{t.auth.passwordLabel}</label>
<div className="relative">
<Lock className={`w-4 h-4 text-slate-500 absolute ${isRtl ? "right-3" : "left-3"} top-2.5`} />
<input
type="password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••••••"
className={`w-full bg-slate-950 border border-slate-800 rounded-lg ${isRtl ? "pr-9 pl-3 text-right" : "pl-9 pr-3 text-left"} py-2 text-xs text-slate-200 focus:outline-none focus:border-cyan-500`}
/>
</div>
</div>
<button
type="submit"
disabled={loading}
className="w-full py-2.5 px-4 bg-cyan-500 hover:bg-cyan-400 text-slate-950 font-bold text-xs rounded-lg transition-all flex items-center justify-center gap-1.5 shadow-md shadow-cyan-950/40 disabled:opacity-50 mt-2 cursor-pointer"
>
{mode === "login" ? <LogIn className="w-3.5 h-3.5" /> : <UserPlus className="w-3.5 h-3.5" />}
{mode === "login" ? t.auth.submitSignIn : t.auth.submitSignUp}
</button>
</form>
<div className="text-center pt-2 border-t border-slate-800 text-xs text-slate-400 font-sans">
{mode === "login" ? (language === "ar" ? "ليس لديك حساب؟" : "Don't have an account?") : (language === "ar" ? "لديك حساب بالفعل؟" : "Already registered?")}{" "}
<button
type="button"
onClick={() => {
setMode(mode === "login" ? "register" : "login");
setError("");
}}
className="text-cyan-400 hover:text-cyan-300 font-semibold underline underline-offset-2 cursor-pointer"
>
{mode === "login" ? (language === "ar" ? "سجل الآن" : "Register") : (language === "ar" ? "تسجيل الدخول" : "Sign In")}
</button>
</div>
</div>
</div>
);
};