✨feat(ui): Add loading states to all authentication buttons
Add loading indicators to improve user experience during authentication processes: - Implement loading states for all login and registration buttons - Add try/catch/finally structure to properly handle async operations - Create wrapper functions for OAuth redirect operations - Set loading state for verification code submission - Update modal confirmation buttons with loading state - Add proper error handling with user feedback - Split generic loading state into specific state variables This change enhances user experience by providing clear visual feedback during authentication actions.
This commit is contained in:
@@ -53,6 +53,15 @@ const LoginForm = () => {
|
|||||||
const [status, setStatus] = useState({});
|
const [status, setStatus] = useState({});
|
||||||
const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
|
const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
|
||||||
const [showEmailLogin, setShowEmailLogin] = useState(false);
|
const [showEmailLogin, setShowEmailLogin] = useState(false);
|
||||||
|
const [wechatLoading, setWechatLoading] = useState(false);
|
||||||
|
const [githubLoading, setGithubLoading] = useState(false);
|
||||||
|
const [oidcLoading, setOidcLoading] = useState(false);
|
||||||
|
const [linuxdoLoading, setLinuxdoLoading] = useState(false);
|
||||||
|
const [emailLoginLoading, setEmailLoginLoading] = useState(false);
|
||||||
|
const [loginLoading, setLoginLoading] = useState(false);
|
||||||
|
const [resetPasswordLoading, setResetPasswordLoading] = useState(false);
|
||||||
|
const [otherLoginOptionsLoading, setOtherLoginOptionsLoading] = useState(false);
|
||||||
|
const [wechatCodeSubmitLoading, setWechatCodeSubmitLoading] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const logo = getLogo();
|
const logo = getLogo();
|
||||||
@@ -79,7 +88,9 @@ const LoginForm = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onWeChatLoginClicked = () => {
|
const onWeChatLoginClicked = () => {
|
||||||
|
setWechatLoading(true);
|
||||||
setShowWeChatLoginModal(true);
|
setShowWeChatLoginModal(true);
|
||||||
|
setWechatLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmitWeChatVerificationCode = async () => {
|
const onSubmitWeChatVerificationCode = async () => {
|
||||||
@@ -87,20 +98,27 @@ const LoginForm = () => {
|
|||||||
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res = await API.get(
|
setWechatCodeSubmitLoading(true);
|
||||||
`/api/oauth/wechat?code=${inputs.wechat_verification_code}`,
|
try {
|
||||||
);
|
const res = await API.get(
|
||||||
const { success, message, data } = res.data;
|
`/api/oauth/wechat?code=${inputs.wechat_verification_code}`,
|
||||||
if (success) {
|
);
|
||||||
userDispatch({ type: 'login', payload: data });
|
const { success, message, data } = res.data;
|
||||||
localStorage.setItem('user', JSON.stringify(data));
|
if (success) {
|
||||||
setUserData(data);
|
userDispatch({ type: 'login', payload: data });
|
||||||
updateAPI();
|
localStorage.setItem('user', JSON.stringify(data));
|
||||||
navigate('/');
|
setUserData(data);
|
||||||
showSuccess('登录成功!');
|
updateAPI();
|
||||||
setShowWeChatLoginModal(false);
|
navigate('/');
|
||||||
} else {
|
showSuccess('登录成功!');
|
||||||
showError(message);
|
setShowWeChatLoginModal(false);
|
||||||
|
} else {
|
||||||
|
showError(message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError('登录失败,请重试');
|
||||||
|
} finally {
|
||||||
|
setWechatCodeSubmitLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -114,33 +132,40 @@ const LoginForm = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSubmitted(true);
|
setSubmitted(true);
|
||||||
if (username && password) {
|
setLoginLoading(true);
|
||||||
const res = await API.post(
|
try {
|
||||||
`/api/user/login?turnstile=${turnstileToken}`,
|
if (username && password) {
|
||||||
{
|
const res = await API.post(
|
||||||
username,
|
`/api/user/login?turnstile=${turnstileToken}`,
|
||||||
password,
|
{
|
||||||
},
|
username,
|
||||||
);
|
password,
|
||||||
const { success, message, data } = res.data;
|
},
|
||||||
if (success) {
|
);
|
||||||
userDispatch({ type: 'login', payload: data });
|
const { success, message, data } = res.data;
|
||||||
setUserData(data);
|
if (success) {
|
||||||
updateAPI();
|
userDispatch({ type: 'login', payload: data });
|
||||||
showSuccess('登录成功!');
|
setUserData(data);
|
||||||
if (username === 'root' && password === '123456') {
|
updateAPI();
|
||||||
Modal.error({
|
showSuccess('登录成功!');
|
||||||
title: '您正在使用默认密码!',
|
if (username === 'root' && password === '123456') {
|
||||||
content: '请立刻修改默认密码!',
|
Modal.error({
|
||||||
centered: true,
|
title: '您正在使用默认密码!',
|
||||||
});
|
content: '请立刻修改默认密码!',
|
||||||
|
centered: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
navigate('/console');
|
||||||
|
} else {
|
||||||
|
showError(message);
|
||||||
}
|
}
|
||||||
navigate('/console');
|
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError('请输入用户名和密码!');
|
||||||
}
|
}
|
||||||
} else {
|
} catch (error) {
|
||||||
showError('请输入用户名和密码!');
|
showError('登录失败,请重试');
|
||||||
|
} finally {
|
||||||
|
setLoginLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,20 +187,81 @@ const LoginForm = () => {
|
|||||||
params[field] = response[field];
|
params[field] = response[field];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const res = await API.get(`/api/oauth/telegram/login`, { params });
|
try {
|
||||||
const { success, message, data } = res.data;
|
const res = await API.get(`/api/oauth/telegram/login`, { params });
|
||||||
if (success) {
|
const { success, message, data } = res.data;
|
||||||
userDispatch({ type: 'login', payload: data });
|
if (success) {
|
||||||
localStorage.setItem('user', JSON.stringify(data));
|
userDispatch({ type: 'login', payload: data });
|
||||||
showSuccess('登录成功!');
|
localStorage.setItem('user', JSON.stringify(data));
|
||||||
setUserData(data);
|
showSuccess('登录成功!');
|
||||||
updateAPI();
|
setUserData(data);
|
||||||
navigate('/');
|
updateAPI();
|
||||||
} else {
|
navigate('/');
|
||||||
showError(message);
|
} else {
|
||||||
|
showError(message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError('登录失败,请重试');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 包装的GitHub登录点击处理
|
||||||
|
const handleGitHubClick = () => {
|
||||||
|
setGithubLoading(true);
|
||||||
|
try {
|
||||||
|
onGitHubOAuthClicked(status.github_client_id);
|
||||||
|
} finally {
|
||||||
|
// 由于重定向,这里不会执行到,但为了完整性添加
|
||||||
|
setTimeout(() => setGithubLoading(false), 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 包装的OIDC登录点击处理
|
||||||
|
const handleOIDCClick = () => {
|
||||||
|
setOidcLoading(true);
|
||||||
|
try {
|
||||||
|
onOIDCClicked(
|
||||||
|
status.oidc_authorization_endpoint,
|
||||||
|
status.oidc_client_id
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
// 由于重定向,这里不会执行到,但为了完整性添加
|
||||||
|
setTimeout(() => setOidcLoading(false), 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 包装的LinuxDO登录点击处理
|
||||||
|
const handleLinuxDOClick = () => {
|
||||||
|
setLinuxdoLoading(true);
|
||||||
|
try {
|
||||||
|
onLinuxDOOAuthClicked(status.linuxdo_client_id);
|
||||||
|
} finally {
|
||||||
|
// 由于重定向,这里不会执行到,但为了完整性添加
|
||||||
|
setTimeout(() => setLinuxdoLoading(false), 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 包装的邮箱登录选项点击处理
|
||||||
|
const handleEmailLoginClick = () => {
|
||||||
|
setEmailLoginLoading(true);
|
||||||
|
setShowEmailLogin(true);
|
||||||
|
setEmailLoginLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 包装的重置密码点击处理
|
||||||
|
const handleResetPasswordClick = () => {
|
||||||
|
setResetPasswordLoading(true);
|
||||||
|
navigate('/reset');
|
||||||
|
setResetPasswordLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 包装的其他登录选项点击处理
|
||||||
|
const handleOtherLoginOptionsClick = () => {
|
||||||
|
setOtherLoginOptionsLoading(true);
|
||||||
|
setShowEmailLogin(false);
|
||||||
|
setOtherLoginOptionsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
const renderOAuthOptions = () => {
|
const renderOAuthOptions = () => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
@@ -199,6 +285,7 @@ const LoginForm = () => {
|
|||||||
icon={<Icon svg={<WeChatIcon />} style={{ color: '#07C160' }} />}
|
icon={<Icon svg={<WeChatIcon />} style={{ color: '#07C160' }} />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={onWeChatLoginClicked}
|
onClick={onWeChatLoginClicked}
|
||||||
|
loading={wechatLoading}
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 微信 继续')}</span>
|
<span className="ml-3">{t('使用 微信 继续')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -211,7 +298,8 @@ const LoginForm = () => {
|
|||||||
type="tertiary"
|
type="tertiary"
|
||||||
icon={<IconGithubLogo size="large" style={{ color: '#24292e' }} />}
|
icon={<IconGithubLogo size="large" style={{ color: '#24292e' }} />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => onGitHubOAuthClicked(status.github_client_id)}
|
onClick={handleGitHubClick}
|
||||||
|
loading={githubLoading}
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 GitHub 继续')}</span>
|
<span className="ml-3">{t('使用 GitHub 继续')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -224,12 +312,8 @@ const LoginForm = () => {
|
|||||||
type="tertiary"
|
type="tertiary"
|
||||||
icon={<OIDCIcon style={{ color: '#1877F2' }} />}
|
icon={<OIDCIcon style={{ color: '#1877F2' }} />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() =>
|
onClick={handleOIDCClick}
|
||||||
onOIDCClicked(
|
loading={oidcLoading}
|
||||||
status.oidc_authorization_endpoint,
|
|
||||||
status.oidc_client_id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 OIDC 继续')}</span>
|
<span className="ml-3">{t('使用 OIDC 继续')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -242,7 +326,8 @@ const LoginForm = () => {
|
|||||||
type="tertiary"
|
type="tertiary"
|
||||||
icon={<LinuxDoIcon style={{ color: '#E95420', width: '20px', height: '20px' }} />}
|
icon={<LinuxDoIcon style={{ color: '#E95420', width: '20px', height: '20px' }} />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => onLinuxDOOAuthClicked(status.linuxdo_client_id)}
|
onClick={handleLinuxDOClick}
|
||||||
|
loading={linuxdoLoading}
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 LinuxDO 继续')}</span>
|
<span className="ml-3">{t('使用 LinuxDO 继续')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -267,7 +352,8 @@ const LoginForm = () => {
|
|||||||
className="w-full h-12 flex items-center justify-center bg-black text-white !rounded-full hover:bg-gray-800 transition-colors"
|
className="w-full h-12 flex items-center justify-center bg-black text-white !rounded-full hover:bg-gray-800 transition-colors"
|
||||||
icon={<IconMail size="large" />}
|
icon={<IconMail size="large" />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => setShowEmailLogin(true)}
|
onClick={handleEmailLoginClick}
|
||||||
|
loading={emailLoginLoading}
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 邮箱 登录')}</span>
|
<span className="ml-3">{t('使用 邮箱 登录')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -340,6 +426,7 @@ const LoginForm = () => {
|
|||||||
htmlType="submit"
|
htmlType="submit"
|
||||||
size="large"
|
size="large"
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
|
loading={loginLoading}
|
||||||
>
|
>
|
||||||
{t('继续')}
|
{t('继续')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -349,7 +436,8 @@ const LoginForm = () => {
|
|||||||
type='tertiary'
|
type='tertiary'
|
||||||
className="w-full !rounded-full"
|
className="w-full !rounded-full"
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => navigate('/reset')}
|
onClick={handleResetPasswordClick}
|
||||||
|
loading={resetPasswordLoading}
|
||||||
>
|
>
|
||||||
{t('忘记密码?')}
|
{t('忘记密码?')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -366,7 +454,8 @@ const LoginForm = () => {
|
|||||||
type="tertiary"
|
type="tertiary"
|
||||||
className="w-full !rounded-full"
|
className="w-full !rounded-full"
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => setShowEmailLogin(false)}
|
onClick={handleOtherLoginOptionsClick}
|
||||||
|
loading={otherLoginOptionsLoading}
|
||||||
>
|
>
|
||||||
{t('其他登录选项')}
|
{t('其他登录选项')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -390,6 +479,9 @@ const LoginForm = () => {
|
|||||||
okText={t('登录')}
|
okText={t('登录')}
|
||||||
size="small"
|
size="small"
|
||||||
centered={true}
|
centered={true}
|
||||||
|
okButtonProps={{
|
||||||
|
loading: wechatCodeSubmitLoading,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<img src={status.wechat_qrcode} alt="微信二维码" className="mb-4" />
|
<img src={status.wechat_qrcode} alt="微信二维码" className="mb-4" />
|
||||||
|
|||||||
@@ -55,6 +55,15 @@ const RegisterForm = () => {
|
|||||||
const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
|
const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
|
||||||
const [showEmailRegister, setShowEmailRegister] = useState(false);
|
const [showEmailRegister, setShowEmailRegister] = useState(false);
|
||||||
const [status, setStatus] = useState({});
|
const [status, setStatus] = useState({});
|
||||||
|
const [wechatLoading, setWechatLoading] = useState(false);
|
||||||
|
const [githubLoading, setGithubLoading] = useState(false);
|
||||||
|
const [oidcLoading, setOidcLoading] = useState(false);
|
||||||
|
const [linuxdoLoading, setLinuxdoLoading] = useState(false);
|
||||||
|
const [emailRegisterLoading, setEmailRegisterLoading] = useState(false);
|
||||||
|
const [registerLoading, setRegisterLoading] = useState(false);
|
||||||
|
const [verificationCodeLoading, setVerificationCodeLoading] = useState(false);
|
||||||
|
const [otherRegisterOptionsLoading, setOtherRegisterOptionsLoading] = useState(false);
|
||||||
|
const [wechatCodeSubmitLoading, setWechatCodeSubmitLoading] = useState(false);
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
const logo = getLogo();
|
const logo = getLogo();
|
||||||
@@ -79,7 +88,9 @@ const RegisterForm = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onWeChatLoginClicked = () => {
|
const onWeChatLoginClicked = () => {
|
||||||
|
setWechatLoading(true);
|
||||||
setShowWeChatLoginModal(true);
|
setShowWeChatLoginModal(true);
|
||||||
|
setWechatLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmitWeChatVerificationCode = async () => {
|
const onSubmitWeChatVerificationCode = async () => {
|
||||||
@@ -87,20 +98,27 @@ const RegisterForm = () => {
|
|||||||
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res = await API.get(
|
setWechatCodeSubmitLoading(true);
|
||||||
`/api/oauth/wechat?code=${inputs.wechat_verification_code}`,
|
try {
|
||||||
);
|
const res = await API.get(
|
||||||
const { success, message, data } = res.data;
|
`/api/oauth/wechat?code=${inputs.wechat_verification_code}`,
|
||||||
if (success) {
|
);
|
||||||
userDispatch({ type: 'login', payload: data });
|
const { success, message, data } = res.data;
|
||||||
localStorage.setItem('user', JSON.stringify(data));
|
if (success) {
|
||||||
setUserData(data);
|
userDispatch({ type: 'login', payload: data });
|
||||||
updateAPI();
|
localStorage.setItem('user', JSON.stringify(data));
|
||||||
navigate('/');
|
setUserData(data);
|
||||||
showSuccess('登录成功!');
|
updateAPI();
|
||||||
setShowWeChatLoginModal(false);
|
navigate('/');
|
||||||
} else {
|
showSuccess('登录成功!');
|
||||||
showError(message);
|
setShowWeChatLoginModal(false);
|
||||||
|
} else {
|
||||||
|
showError(message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError('登录失败,请重试');
|
||||||
|
} finally {
|
||||||
|
setWechatCodeSubmitLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,23 +140,28 @@ const RegisterForm = () => {
|
|||||||
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoading(true);
|
setRegisterLoading(true);
|
||||||
if (!affCode) {
|
try {
|
||||||
affCode = localStorage.getItem('aff');
|
if (!affCode) {
|
||||||
|
affCode = localStorage.getItem('aff');
|
||||||
|
}
|
||||||
|
inputs.aff_code = affCode;
|
||||||
|
const res = await API.post(
|
||||||
|
`/api/user/register?turnstile=${turnstileToken}`,
|
||||||
|
inputs,
|
||||||
|
);
|
||||||
|
const { success, message } = res.data;
|
||||||
|
if (success) {
|
||||||
|
navigate('/login');
|
||||||
|
showSuccess('注册成功!');
|
||||||
|
} else {
|
||||||
|
showError(message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError('注册失败,请重试');
|
||||||
|
} finally {
|
||||||
|
setRegisterLoading(false);
|
||||||
}
|
}
|
||||||
inputs.aff_code = affCode;
|
|
||||||
const res = await API.post(
|
|
||||||
`/api/user/register?turnstile=${turnstileToken}`,
|
|
||||||
inputs,
|
|
||||||
);
|
|
||||||
const { success, message } = res.data;
|
|
||||||
if (success) {
|
|
||||||
navigate('/login');
|
|
||||||
showSuccess('注册成功!');
|
|
||||||
} else {
|
|
||||||
showError(message);
|
|
||||||
}
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,17 +171,64 @@ const RegisterForm = () => {
|
|||||||
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoading(true);
|
setVerificationCodeLoading(true);
|
||||||
const res = await API.get(
|
try {
|
||||||
`/api/verification?email=${inputs.email}&turnstile=${turnstileToken}`,
|
const res = await API.get(
|
||||||
);
|
`/api/verification?email=${inputs.email}&turnstile=${turnstileToken}`,
|
||||||
const { success, message } = res.data;
|
);
|
||||||
if (success) {
|
const { success, message } = res.data;
|
||||||
showSuccess('验证码发送成功,请检查你的邮箱!');
|
if (success) {
|
||||||
} else {
|
showSuccess('验证码发送成功,请检查你的邮箱!');
|
||||||
showError(message);
|
} else {
|
||||||
|
showError(message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError('发送验证码失败,请重试');
|
||||||
|
} finally {
|
||||||
|
setVerificationCodeLoading(false);
|
||||||
}
|
}
|
||||||
setLoading(false);
|
};
|
||||||
|
|
||||||
|
const handleGitHubClick = () => {
|
||||||
|
setGithubLoading(true);
|
||||||
|
try {
|
||||||
|
onGitHubOAuthClicked(status.github_client_id);
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => setGithubLoading(false), 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOIDCClick = () => {
|
||||||
|
setOidcLoading(true);
|
||||||
|
try {
|
||||||
|
onOIDCClicked(
|
||||||
|
status.oidc_authorization_endpoint,
|
||||||
|
status.oidc_client_id
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => setOidcLoading(false), 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLinuxDOClick = () => {
|
||||||
|
setLinuxdoLoading(true);
|
||||||
|
try {
|
||||||
|
onLinuxDOOAuthClicked(status.linuxdo_client_id);
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => setLinuxdoLoading(false), 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEmailRegisterClick = () => {
|
||||||
|
setEmailRegisterLoading(true);
|
||||||
|
setShowEmailRegister(true);
|
||||||
|
setEmailRegisterLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOtherRegisterOptionsClick = () => {
|
||||||
|
setOtherRegisterOptionsLoading(true);
|
||||||
|
setShowEmailRegister(false);
|
||||||
|
setOtherRegisterOptionsLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onTelegramLoginClicked = async (response) => {
|
const onTelegramLoginClicked = async (response) => {
|
||||||
@@ -178,17 +248,21 @@ const RegisterForm = () => {
|
|||||||
params[field] = response[field];
|
params[field] = response[field];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const res = await API.get(`/api/oauth/telegram/login`, { params });
|
try {
|
||||||
const { success, message, data } = res.data;
|
const res = await API.get(`/api/oauth/telegram/login`, { params });
|
||||||
if (success) {
|
const { success, message, data } = res.data;
|
||||||
userDispatch({ type: 'login', payload: data });
|
if (success) {
|
||||||
localStorage.setItem('user', JSON.stringify(data));
|
userDispatch({ type: 'login', payload: data });
|
||||||
showSuccess('登录成功!');
|
localStorage.setItem('user', JSON.stringify(data));
|
||||||
setUserData(data);
|
showSuccess('登录成功!');
|
||||||
updateAPI();
|
setUserData(data);
|
||||||
navigate('/');
|
updateAPI();
|
||||||
} else {
|
navigate('/');
|
||||||
showError(message);
|
} else {
|
||||||
|
showError(message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError('登录失败,请重试');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -215,6 +289,7 @@ const RegisterForm = () => {
|
|||||||
icon={<Icon svg={<WeChatIcon />} style={{ color: '#07C160' }} />}
|
icon={<Icon svg={<WeChatIcon />} style={{ color: '#07C160' }} />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={onWeChatLoginClicked}
|
onClick={onWeChatLoginClicked}
|
||||||
|
loading={wechatLoading}
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 微信 继续')}</span>
|
<span className="ml-3">{t('使用 微信 继续')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -227,7 +302,8 @@ const RegisterForm = () => {
|
|||||||
type="tertiary"
|
type="tertiary"
|
||||||
icon={<IconGithubLogo size="large" style={{ color: '#24292e' }} />}
|
icon={<IconGithubLogo size="large" style={{ color: '#24292e' }} />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => onGitHubOAuthClicked(status.github_client_id)}
|
onClick={handleGitHubClick}
|
||||||
|
loading={githubLoading}
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 GitHub 继续')}</span>
|
<span className="ml-3">{t('使用 GitHub 继续')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -240,12 +316,8 @@ const RegisterForm = () => {
|
|||||||
type="tertiary"
|
type="tertiary"
|
||||||
icon={<OIDCIcon style={{ color: '#1877F2' }} />}
|
icon={<OIDCIcon style={{ color: '#1877F2' }} />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() =>
|
onClick={handleOIDCClick}
|
||||||
onOIDCClicked(
|
loading={oidcLoading}
|
||||||
status.oidc_authorization_endpoint,
|
|
||||||
status.oidc_client_id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 OIDC 继续')}</span>
|
<span className="ml-3">{t('使用 OIDC 继续')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -258,7 +330,8 @@ const RegisterForm = () => {
|
|||||||
type="tertiary"
|
type="tertiary"
|
||||||
icon={<LinuxDoIcon style={{ color: '#E95420', width: '20px', height: '20px' }} />}
|
icon={<LinuxDoIcon style={{ color: '#E95420', width: '20px', height: '20px' }} />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => onLinuxDOOAuthClicked(status.linuxdo_client_id)}
|
onClick={handleLinuxDOClick}
|
||||||
|
loading={linuxdoLoading}
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 LinuxDO 继续')}</span>
|
<span className="ml-3">{t('使用 LinuxDO 继续')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -283,7 +356,8 @@ const RegisterForm = () => {
|
|||||||
className="w-full h-12 flex items-center justify-center bg-black text-white !rounded-full hover:bg-gray-800 transition-colors"
|
className="w-full h-12 flex items-center justify-center bg-black text-white !rounded-full hover:bg-gray-800 transition-colors"
|
||||||
icon={<IconMail size="large" />}
|
icon={<IconMail size="large" />}
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => setShowEmailRegister(true)}
|
onClick={handleEmailRegisterClick}
|
||||||
|
loading={emailRegisterLoading}
|
||||||
>
|
>
|
||||||
<span className="ml-3">{t('使用 邮箱 注册')}</span>
|
<span className="ml-3">{t('使用 邮箱 注册')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -375,7 +449,7 @@ const RegisterForm = () => {
|
|||||||
suffix={
|
suffix={
|
||||||
<Button
|
<Button
|
||||||
onClick={sendVerificationCode}
|
onClick={sendVerificationCode}
|
||||||
disabled={loading}
|
loading={verificationCodeLoading}
|
||||||
size="small"
|
size="small"
|
||||||
className="!rounded-md mr-2"
|
className="!rounded-md mr-2"
|
||||||
>
|
>
|
||||||
@@ -404,6 +478,7 @@ const RegisterForm = () => {
|
|||||||
htmlType="submit"
|
htmlType="submit"
|
||||||
size="large"
|
size="large"
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
|
loading={registerLoading}
|
||||||
>
|
>
|
||||||
{t('注册')}
|
{t('注册')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -420,7 +495,8 @@ const RegisterForm = () => {
|
|||||||
type="tertiary"
|
type="tertiary"
|
||||||
className="w-full !rounded-full"
|
className="w-full !rounded-full"
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => setShowEmailRegister(false)}
|
onClick={handleOtherRegisterOptionsClick}
|
||||||
|
loading={otherRegisterOptionsLoading}
|
||||||
>
|
>
|
||||||
{t('其他注册选项')}
|
{t('其他注册选项')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -436,7 +512,6 @@ const RegisterForm = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 微信登录模态框
|
|
||||||
const renderWeChatLoginModal = () => {
|
const renderWeChatLoginModal = () => {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@@ -448,6 +523,9 @@ const RegisterForm = () => {
|
|||||||
okText={t('登录')}
|
okText={t('登录')}
|
||||||
size="small"
|
size="small"
|
||||||
centered={true}
|
centered={true}
|
||||||
|
okButtonProps={{
|
||||||
|
loading: wechatCodeSubmitLoading,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<img src={status.wechat_qrcode} alt="微信二维码" className="mb-4" />
|
<img src={status.wechat_qrcode} alt="微信二维码" className="mb-4" />
|
||||||
@@ -472,7 +550,6 @@ const RegisterForm = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen relative flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8 overflow-hidden">
|
<div className="min-h-screen relative flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8 overflow-hidden">
|
||||||
{/* 背景图片容器 - 放大并保持居中 */}
|
|
||||||
<div
|
<div
|
||||||
className="absolute inset-0 z-0 bg-cover bg-center scale-125 opacity-100"
|
className="absolute inset-0 z-0 bg-cover bg-center scale-125 opacity-100"
|
||||||
style={{
|
style={{
|
||||||
@@ -480,7 +557,6 @@ const RegisterForm = () => {
|
|||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
{/* 半透明遮罩层 */}
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-br from-teal-500/30 via-blue-500/30 to-purple-500/30 backdrop-blur-sm z-0"></div>
|
<div className="absolute inset-0 bg-gradient-to-br from-teal-500/30 via-blue-500/30 to-purple-500/30 backdrop-blur-sm z-0"></div>
|
||||||
|
|
||||||
<div className="w-full max-w-md relative z-10">
|
<div className="w-full max-w-md relative z-10">
|
||||||
|
|||||||
Reference in New Issue
Block a user