webapps/console/components/SignInOrUp/EmailFirstLogin.tsx
Rama newjitsu · réplica de lectura del repositorio original.
import React, { useState } from "react";
import { Alert, Button, Input, Spin } from "antd";
import { LockOutlined, MailOutlined } from "@ant-design/icons";
import { rpc } from "juava";
import { AuthType } from "./SignInOrUp";
type AuthMethod = {
type: AuthType;
oidcProviderId?: string;
oidcProviderName?: string;
};
interface EmailFirstLoginProps {
onPasswordLogin: (email: string, password: string, type: AuthType) => Promise<void>;
onSSOLogin: (type: AuthType, providerId: string, loginHint?: string) => Promise<void>;
signup?: boolean; // Optional prop to indicate if this is a signup flow
}
export const EmailFirstLogin: React.FC<EmailFirstLoginProps> = ({ onPasswordLogin, onSSOLogin, signup }) => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [authMethod, setAuthMethod] = useState<AuthMethod | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [checkingEmail, setCheckingEmail] = useState(false);
const checkAuthMethod = async () => {
if (!email || !email.includes("@")) {
setError("Please enter a valid email address");
return;
}
setCheckingEmail(true);
setError(null);
try {
const result = await rpc("/api/auth/check-email", {
body: { email },
});
const authMethod = result[0];
setAuthMethod(authMethod);
// Auto-trigger social login if applicable
switch (authMethod.type) {
case "firebase-google":
case "firebase-github":
case "nextauth-github":
case "nextauth-oidc":
await onSSOLogin(authMethod.type, authMethod.type, email);
break;
case "dynamic-oidc":
await onSSOLogin(authMethod.type, authMethod.oidcProviderId, email);
}
} catch (err: any) {
setError("Failed to check authentication method. Please try again.");
console.error("Error checking auth method:", err);
} finally {
setCheckingEmail(false);
}
};
const handlePasswordLogin = async () => {
if (!email || !password) {
setError("Please enter both email and password");
return;
}
setLoading(true);
setError(null);
try {
await onPasswordLogin(email, password, authMethod?.type!);
} catch (err: any) {
setError(err.message || "Login failed. Please check your credentials.");
} finally {
setLoading(false);
}
};
const renderAuthForm = () => {
if (!authMethod) {
return null;
}
switch (authMethod.type) {
case "firebase-password":
case "nextauth-credentials":
return (
<div className="mt-4">
<div className="font-bold text-textLight tracking-wide pb-2 flex items-center">
<LockOutlined className="mr-2" />
Password
</div>
<Input.Password
size="large"
value={password}
onChange={e => setPassword(e.target.value)}
placeholder="Enter your password"
onPressEnter={handlePasswordLogin}
/>
<div className="mt-2 text-right">
<a className="text-sm hover:text-primary" href={`/reset-password?email=${encodeURIComponent(email)}`}>
Forgot password?
</a>
</div>
<Button className="w-full mt-4" type="primary" size="large" loading={loading} onClick={handlePasswordLogin}>
{signup ? "Sign Up" : "Sign in"}
</Button>
</div>
);
case "firebase-google":
return (
<div className="mt-4">
<Alert message="Redirecting to Google login..." type="info" showIcon icon={<Spin />} />
</div>
);
case "firebase-github":
case "nextauth-github":
return (
<div className="mt-4">
<Alert message="Redirecting to GitHub login..." type="info" showIcon icon={<Spin />} />
</div>
);
case "nextauth-oidc":
return (
<div className="mt-4">
<Alert message="Redirecting to SSO provider..." type="info" showIcon icon={<Spin />} />
</div>
);
case "dynamic-oidc":
return (
<div className="mt-4">
<Alert
message={`Redirecting to ${authMethod.oidcProviderName || "SSO provider"}...`}
type="info"
showIcon
icon={<Spin />}
/>
</div>
);
case "none":
return (
<div className="mt-4">
<Alert
message="No authorization method configured"
description="Please contact your administrator to set up an authentication method."
type="warning"
showIcon
/>
</div>
);
default:
return null;
}
};
return (
<div className="w-full">
<div className="space-y-4">
<div>
<div className="font-bold text-textLight tracking-wide pb-2 flex items-center">
<MailOutlined className="mr-2" />
Email
</div>
<Input
size="large"
value={email}
onChange={e => {
setEmail(e.target.value);
setAuthMethod(null);
setError(null);
}}
placeholder="Enter your email address"
onPressEnter={checkAuthMethod}
disabled={checkingEmail || loading}
/>
</div>
{!authMethod && (
<Button
className="w-full"
type="primary"
size="large"
loading={checkingEmail}
onClick={checkAuthMethod}
disabled={!email || !email.includes("@")}
>
Continue
</Button>
)}
{error && (
<Alert message="Error" description={error} type="error" showIcon closable onClose={() => setError(null)} />
)}
{renderAuthForm()}
</div>
</div>
);
};