feat: add user agreement and privacy policy to login page
This commit is contained in:
@@ -37,7 +37,7 @@ import {
|
|||||||
isPasskeySupported,
|
isPasskeySupported,
|
||||||
} from '../../helpers';
|
} from '../../helpers';
|
||||||
import Turnstile from 'react-turnstile';
|
import Turnstile from 'react-turnstile';
|
||||||
import { Button, Card, Divider, Form, Icon, Modal } from '@douyinfe/semi-ui';
|
import { Button, Card, Checkbox, Divider, Form, Icon, Modal } from '@douyinfe/semi-ui';
|
||||||
import Title from '@douyinfe/semi-ui/lib/es/typography/title';
|
import Title from '@douyinfe/semi-ui/lib/es/typography/title';
|
||||||
import Text from '@douyinfe/semi-ui/lib/es/typography/text';
|
import Text from '@douyinfe/semi-ui/lib/es/typography/text';
|
||||||
import TelegramLoginButton from 'react-telegram-login';
|
import TelegramLoginButton from 'react-telegram-login';
|
||||||
@@ -84,6 +84,9 @@ const LoginForm = () => {
|
|||||||
const [showTwoFA, setShowTwoFA] = useState(false);
|
const [showTwoFA, setShowTwoFA] = useState(false);
|
||||||
const [passkeySupported, setPasskeySupported] = useState(false);
|
const [passkeySupported, setPasskeySupported] = useState(false);
|
||||||
const [passkeyLoading, setPasskeyLoading] = useState(false);
|
const [passkeyLoading, setPasskeyLoading] = useState(false);
|
||||||
|
const [agreedToTerms, setAgreedToTerms] = useState(false);
|
||||||
|
const [hasUserAgreement, setHasUserAgreement] = useState(false);
|
||||||
|
const [hasPrivacyPolicy, setHasPrivacyPolicy] = useState(false);
|
||||||
|
|
||||||
const logo = getLogo();
|
const logo = getLogo();
|
||||||
const systemName = getSystemName();
|
const systemName = getSystemName();
|
||||||
@@ -103,6 +106,10 @@ const LoginForm = () => {
|
|||||||
setTurnstileEnabled(true);
|
setTurnstileEnabled(true);
|
||||||
setTurnstileSiteKey(status.turnstile_site_key);
|
setTurnstileSiteKey(status.turnstile_site_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从 status 获取用户协议和隐私政策的启用状态
|
||||||
|
setHasUserAgreement(status.user_agreement_enabled || false);
|
||||||
|
setHasPrivacyPolicy(status.privacy_policy_enabled || false);
|
||||||
}, [status]);
|
}, [status]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -118,6 +125,10 @@ const LoginForm = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onWeChatLoginClicked = () => {
|
const onWeChatLoginClicked = () => {
|
||||||
|
if ((hasUserAgreement || hasPrivacyPolicy) && !agreedToTerms) {
|
||||||
|
showInfo(t('请先阅读并同意用户协议和隐私政策'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
setWechatLoading(true);
|
setWechatLoading(true);
|
||||||
setShowWeChatLoginModal(true);
|
setShowWeChatLoginModal(true);
|
||||||
setWechatLoading(false);
|
setWechatLoading(false);
|
||||||
@@ -157,6 +168,10 @@ const LoginForm = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleSubmit(e) {
|
async function handleSubmit(e) {
|
||||||
|
if ((hasUserAgreement || hasPrivacyPolicy) && !agreedToTerms) {
|
||||||
|
showInfo(t('请先阅读并同意用户协议和隐私政策'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (turnstileEnabled && turnstileToken === '') {
|
if (turnstileEnabled && turnstileToken === '') {
|
||||||
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
||||||
return;
|
return;
|
||||||
@@ -208,6 +223,10 @@ const LoginForm = () => {
|
|||||||
|
|
||||||
// 添加Telegram登录处理函数
|
// 添加Telegram登录处理函数
|
||||||
const onTelegramLoginClicked = async (response) => {
|
const onTelegramLoginClicked = async (response) => {
|
||||||
|
if ((hasUserAgreement || hasPrivacyPolicy) && !agreedToTerms) {
|
||||||
|
showInfo(t('请先阅读并同意用户协议和隐私政策'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
const fields = [
|
const fields = [
|
||||||
'id',
|
'id',
|
||||||
'first_name',
|
'first_name',
|
||||||
@@ -244,6 +263,10 @@ const LoginForm = () => {
|
|||||||
|
|
||||||
// 包装的GitHub登录点击处理
|
// 包装的GitHub登录点击处理
|
||||||
const handleGitHubClick = () => {
|
const handleGitHubClick = () => {
|
||||||
|
if ((hasUserAgreement || hasPrivacyPolicy) && !agreedToTerms) {
|
||||||
|
showInfo(t('请先阅读并同意用户协议和隐私政策'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
setGithubLoading(true);
|
setGithubLoading(true);
|
||||||
try {
|
try {
|
||||||
onGitHubOAuthClicked(status.github_client_id);
|
onGitHubOAuthClicked(status.github_client_id);
|
||||||
@@ -255,6 +278,10 @@ const LoginForm = () => {
|
|||||||
|
|
||||||
// 包装的OIDC登录点击处理
|
// 包装的OIDC登录点击处理
|
||||||
const handleOIDCClick = () => {
|
const handleOIDCClick = () => {
|
||||||
|
if ((hasUserAgreement || hasPrivacyPolicy) && !agreedToTerms) {
|
||||||
|
showInfo(t('请先阅读并同意用户协议和隐私政策'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
setOidcLoading(true);
|
setOidcLoading(true);
|
||||||
try {
|
try {
|
||||||
onOIDCClicked(status.oidc_authorization_endpoint, status.oidc_client_id);
|
onOIDCClicked(status.oidc_authorization_endpoint, status.oidc_client_id);
|
||||||
@@ -266,6 +293,10 @@ const LoginForm = () => {
|
|||||||
|
|
||||||
// 包装的LinuxDO登录点击处理
|
// 包装的LinuxDO登录点击处理
|
||||||
const handleLinuxDOClick = () => {
|
const handleLinuxDOClick = () => {
|
||||||
|
if ((hasUserAgreement || hasPrivacyPolicy) && !agreedToTerms) {
|
||||||
|
showInfo(t('请先阅读并同意用户协议和隐私政策'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
setLinuxdoLoading(true);
|
setLinuxdoLoading(true);
|
||||||
try {
|
try {
|
||||||
onLinuxDOOAuthClicked(status.linuxdo_client_id);
|
onLinuxDOOAuthClicked(status.linuxdo_client_id);
|
||||||
@@ -283,6 +314,10 @@ const LoginForm = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePasskeyLogin = async () => {
|
const handlePasskeyLogin = async () => {
|
||||||
|
if ((hasUserAgreement || hasPrivacyPolicy) && !agreedToTerms) {
|
||||||
|
showInfo(t('请先阅读并同意用户协议和隐私政策'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!passkeySupported) {
|
if (!passkeySupported) {
|
||||||
showInfo('当前环境无法使用 Passkey 登录');
|
showInfo('当前环境无法使用 Passkey 登录');
|
||||||
return;
|
return;
|
||||||
@@ -486,6 +521,44 @@ const LoginForm = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{(hasUserAgreement || hasPrivacyPolicy) && (
|
||||||
|
<div className='mt-6'>
|
||||||
|
<Checkbox
|
||||||
|
checked={agreedToTerms}
|
||||||
|
onChange={(e) => setAgreedToTerms(e.target.checked)}
|
||||||
|
>
|
||||||
|
<Text size='small' className='text-gray-600'>
|
||||||
|
{t('我已阅读并同意')}
|
||||||
|
{hasUserAgreement && (
|
||||||
|
<>
|
||||||
|
<a
|
||||||
|
href='/user-agreement'
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
className='text-blue-600 hover:text-blue-800 mx-1'
|
||||||
|
>
|
||||||
|
{t('用户协议')}
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{hasUserAgreement && hasPrivacyPolicy && t('和')}
|
||||||
|
{hasPrivacyPolicy && (
|
||||||
|
<>
|
||||||
|
<a
|
||||||
|
href='/privacy-policy'
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
className='text-blue-600 hover:text-blue-800 mx-1'
|
||||||
|
>
|
||||||
|
{t('隐私政策')}
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{!status.self_use_mode_enabled && (
|
{!status.self_use_mode_enabled && (
|
||||||
<div className='mt-6 text-center text-sm'>
|
<div className='mt-6 text-center text-sm'>
|
||||||
<Text>
|
<Text>
|
||||||
@@ -554,6 +627,44 @@ const LoginForm = () => {
|
|||||||
prefix={<IconLock />}
|
prefix={<IconLock />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{(hasUserAgreement || hasPrivacyPolicy) && (
|
||||||
|
<div className='pt-4'>
|
||||||
|
<Checkbox
|
||||||
|
checked={agreedToTerms}
|
||||||
|
onChange={(e) => setAgreedToTerms(e.target.checked)}
|
||||||
|
>
|
||||||
|
<Text size='small' className='text-gray-600'>
|
||||||
|
{t('我已阅读并同意')}
|
||||||
|
{hasUserAgreement && (
|
||||||
|
<>
|
||||||
|
<a
|
||||||
|
href='/user-agreement'
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
className='text-blue-600 hover:text-blue-800 mx-1'
|
||||||
|
>
|
||||||
|
{t('用户协议')}
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{hasUserAgreement && hasPrivacyPolicy && t('和')}
|
||||||
|
{hasPrivacyPolicy && (
|
||||||
|
<>
|
||||||
|
<a
|
||||||
|
href='/privacy-policy'
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
className='text-blue-600 hover:text-blue-800 mx-1'
|
||||||
|
>
|
||||||
|
{t('隐私政策')}
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className='space-y-2 pt-2'>
|
<div className='space-y-2 pt-2'>
|
||||||
<Button
|
<Button
|
||||||
theme='solid'
|
theme='solid'
|
||||||
@@ -562,6 +673,7 @@ const LoginForm = () => {
|
|||||||
htmlType='submit'
|
htmlType='submit'
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
loading={loginLoading}
|
loading={loginLoading}
|
||||||
|
disabled={(hasUserAgreement || hasPrivacyPolicy) && !agreedToTerms}
|
||||||
>
|
>
|
||||||
{t('继续')}
|
{t('继续')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import {
|
|||||||
setUserData,
|
setUserData,
|
||||||
} from '../../helpers';
|
} from '../../helpers';
|
||||||
import Turnstile from 'react-turnstile';
|
import Turnstile from 'react-turnstile';
|
||||||
import { Button, Card, Divider, Form, Icon, Modal } from '@douyinfe/semi-ui';
|
import { Button, Card, Checkbox, Divider, Form, Icon, Modal } from '@douyinfe/semi-ui';
|
||||||
import Title from '@douyinfe/semi-ui/lib/es/typography/title';
|
import Title from '@douyinfe/semi-ui/lib/es/typography/title';
|
||||||
import Text from '@douyinfe/semi-ui/lib/es/typography/text';
|
import Text from '@douyinfe/semi-ui/lib/es/typography/text';
|
||||||
import {
|
import {
|
||||||
@@ -514,9 +514,9 @@ const RegisterForm = () => {
|
|||||||
|
|
||||||
{(hasUserAgreement || hasPrivacyPolicy) && (
|
{(hasUserAgreement || hasPrivacyPolicy) && (
|
||||||
<div className='pt-4'>
|
<div className='pt-4'>
|
||||||
<Form.Checkbox
|
<Checkbox
|
||||||
checked={agreedToTerms}
|
checked={agreedToTerms}
|
||||||
onChange={(checked) => setAgreedToTerms(checked)}
|
onChange={(e) => setAgreedToTerms(e.target.checked)}
|
||||||
>
|
>
|
||||||
<Text size='small' className='text-gray-600'>
|
<Text size='small' className='text-gray-600'>
|
||||||
{t('我已阅读并同意')}
|
{t('我已阅读并同意')}
|
||||||
@@ -546,7 +546,7 @@ const RegisterForm = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</Form.Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user