mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
✨ feat(auth): show last used auth provider on sign-in page (#12737)
This commit is contained in:
@@ -86,6 +86,7 @@
|
||||
"betterAuth.signin.forgotPasswordSent": "Password reset link sent, please check your email",
|
||||
"betterAuth.signin.invalidReferralCodeContent": "The referral code \"{{code}}\" you used is invalid or expired. Do you want to continue signing in?",
|
||||
"betterAuth.signin.invalidReferralCodeTitle": "Invalid Referral Code",
|
||||
"betterAuth.signin.lastUsed": "Last used",
|
||||
"betterAuth.signin.magicLinkButton": "Send sign-in link",
|
||||
"betterAuth.signin.magicLinkError": "Failed to send sign-in link, please try again later",
|
||||
"betterAuth.signin.magicLinkSent": "Sign-in link sent, please check your email",
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
"betterAuth.signin.forgotPasswordSent": "已发送重置链接,请检查邮箱",
|
||||
"betterAuth.signin.invalidReferralCodeContent": "您使用的邀请码 \"{{code}}\" 无效或已过期。是否继续登录?",
|
||||
"betterAuth.signin.invalidReferralCodeTitle": "无效的邀请码",
|
||||
"betterAuth.signin.lastUsed": "上次使用",
|
||||
"betterAuth.signin.magicLinkButton": "发送登录链接",
|
||||
"betterAuth.signin.magicLinkError": "发送遇到了问题。你可以稍后再试",
|
||||
"betterAuth.signin.magicLinkSent": "登录链接已发送,请查收邮箱",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BRANDING_NAME } from '@lobechat/business-const';
|
||||
import { Alert, Button, Flexbox, Icon, Input, Skeleton, Text } from '@lobehub/ui';
|
||||
import { type FormInstance, type InputRef } from 'antd';
|
||||
import { Divider, Form } from 'antd';
|
||||
import { Badge, Divider, Form } from 'antd';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ChevronRight, Mail } from 'lucide-react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
@@ -27,6 +27,7 @@ export interface SignInEmailStepProps {
|
||||
disableEmailPassword?: boolean;
|
||||
form: FormInstance<{ email: string }>;
|
||||
isSocialOnly: boolean;
|
||||
lastAuthProvider?: string | null;
|
||||
loading: boolean;
|
||||
oAuthSSOProviders: string[];
|
||||
onCheckUser: (values: { email: string }) => Promise<void>;
|
||||
@@ -40,6 +41,7 @@ export const SignInEmailStep = ({
|
||||
disableEmailPassword,
|
||||
form,
|
||||
isSocialOnly,
|
||||
lastAuthProvider,
|
||||
loading,
|
||||
oAuthSSOProviders,
|
||||
serverConfigInit,
|
||||
@@ -114,27 +116,41 @@ export const SignInEmailStep = ({
|
||||
)}
|
||||
{serverConfigInit && oAuthSSOProviders.length > 0 && (
|
||||
<Flexbox gap={12}>
|
||||
{oAuthSSOProviders.map((provider) => (
|
||||
<Button
|
||||
block
|
||||
key={provider}
|
||||
loading={socialLoading === provider}
|
||||
size="large"
|
||||
icon={
|
||||
<Icon
|
||||
icon={AuthIcons(provider, 18)}
|
||||
style={{
|
||||
left: 12,
|
||||
position: 'absolute',
|
||||
top: 13,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
onClick={() => onSocialSignIn(provider)}
|
||||
>
|
||||
{getProviderLabel(provider)}
|
||||
</Button>
|
||||
))}
|
||||
{oAuthSSOProviders.map((provider) => {
|
||||
const button = (
|
||||
<Button
|
||||
block
|
||||
key={provider}
|
||||
loading={socialLoading === provider}
|
||||
size="large"
|
||||
icon={
|
||||
<Icon
|
||||
icon={AuthIcons(provider, 18)}
|
||||
style={{
|
||||
left: 12,
|
||||
position: 'absolute',
|
||||
top: 13,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
onClick={() => onSocialSignIn(provider)}
|
||||
>
|
||||
{getProviderLabel(provider)}
|
||||
</Button>
|
||||
);
|
||||
return provider === lastAuthProvider ? (
|
||||
<Badge.Ribbon
|
||||
color="var(--ant-color-info-fill-tertiary)"
|
||||
key={provider}
|
||||
styles={{ content: { color: 'var(--ant-color-info)' } }}
|
||||
text={t('betterAuth.signin.lastUsed')}
|
||||
>
|
||||
{button}
|
||||
</Badge.Ribbon>
|
||||
) : (
|
||||
button
|
||||
);
|
||||
})}
|
||||
{!disableEmailPassword && divider}
|
||||
</Flexbox>
|
||||
)}
|
||||
|
||||
@@ -19,6 +19,7 @@ const SignInPage = () => {
|
||||
handleSignIn,
|
||||
handleSocialSignIn,
|
||||
isSocialOnly,
|
||||
lastAuthProvider,
|
||||
loading,
|
||||
oAuthSSOProviders,
|
||||
serverConfigInit,
|
||||
@@ -33,6 +34,7 @@ const SignInPage = () => {
|
||||
disableEmailPassword={disableEmailPassword}
|
||||
form={form as any}
|
||||
isSocialOnly={isSocialOnly}
|
||||
lastAuthProvider={lastAuthProvider}
|
||||
loading={loading}
|
||||
oAuthSSOProviders={oAuthSSOProviders}
|
||||
serverConfigInit={serverConfigInit}
|
||||
|
||||
@@ -14,6 +14,8 @@ import { isBuiltinProvider, normalizeProviderId } from '@/libs/better-auth/utils
|
||||
import { useAuthServerConfigStore } from '../_layout/AuthServerConfigProvider';
|
||||
import { EMAIL_REGEX, USERNAME_REGEX } from './SignInEmailStep';
|
||||
|
||||
const LAST_AUTH_PROVIDER_KEY = 'lobehub:auth:last-provider:v1';
|
||||
|
||||
type Step = 'email' | 'password';
|
||||
|
||||
interface SignInFormValues {
|
||||
@@ -40,6 +42,13 @@ export const useSignIn = () => {
|
||||
const [step, setStep] = useState<Step>('email');
|
||||
const [email, setEmail] = useState('');
|
||||
const [isSocialOnly, setIsSocialOnly] = useState(false);
|
||||
const [lastAuthProvider] = useState(() => {
|
||||
try {
|
||||
return localStorage.getItem(LAST_AUTH_PROVIDER_KEY);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
const serverConfigInit = useAuthServerConfigStore((s) => s.serverConfigInit);
|
||||
const oAuthSSOProviders = useAuthServerConfigStore((s) => s.serverConfig.oAuthSSOProviders) || [];
|
||||
const { ssoProviders, preSocialSigninCheck, getAdditionalData } = useBusinessSignin();
|
||||
@@ -194,6 +203,10 @@ export const useSignIn = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
localStorage.setItem(LAST_AUTH_PROVIDER_KEY, provider);
|
||||
} catch {}
|
||||
|
||||
const callbackUrl = searchParams.get('callbackUrl') || '/';
|
||||
const additionalData = await getAdditionalData();
|
||||
const result = isBuiltinProvider(normalizedProvider)
|
||||
@@ -243,6 +256,15 @@ export const useSignIn = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const resolvedProviders = ENABLE_BUSINESS_FEATURES ? ssoProviders : oAuthSSOProviders;
|
||||
const sortedProviders = lastAuthProvider
|
||||
? [...resolvedProviders].sort((a, b) => {
|
||||
if (a === lastAuthProvider) return -1;
|
||||
if (b === lastAuthProvider) return 1;
|
||||
return 0;
|
||||
})
|
||||
: resolvedProviders;
|
||||
|
||||
return {
|
||||
disableEmailPassword,
|
||||
email,
|
||||
@@ -254,8 +276,9 @@ export const useSignIn = () => {
|
||||
handleSignIn,
|
||||
handleSocialSignIn,
|
||||
isSocialOnly,
|
||||
lastAuthProvider,
|
||||
loading,
|
||||
oAuthSSOProviders: ENABLE_BUSINESS_FEATURES ? ssoProviders : oAuthSSOProviders,
|
||||
oAuthSSOProviders: sortedProviders,
|
||||
serverConfigInit: ENABLE_BUSINESS_FEATURES ? true : serverConfigInit,
|
||||
socialLoading,
|
||||
step,
|
||||
|
||||
@@ -92,6 +92,7 @@ export default {
|
||||
'betterAuth.signin.magicLinkButton': 'Send sign-in link',
|
||||
'betterAuth.signin.magicLinkError': 'Failed to send sign-in link, please try again later',
|
||||
'betterAuth.signin.magicLinkSent': 'Sign-in link sent, please check your email',
|
||||
'betterAuth.signin.lastUsed': 'Last used',
|
||||
'betterAuth.signin.nextStep': 'Next',
|
||||
'betterAuth.signin.noAccount': "Don't have an account?",
|
||||
'betterAuth.signin.orContinueWith': 'OR',
|
||||
|
||||
Reference in New Issue
Block a user