fix:同意隐私

This commit is contained in:
吕新雨
2026-02-05 16:33:58 +08:00
parent 8e71503169
commit 1e1e49ea57
5 changed files with 138 additions and 53 deletions

View File

@@ -1,12 +1,13 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Dimensions, Platform, Alert, Image } from 'react-native';
import { useRouter } from 'expo-router';
import * as WebBrowser from 'expo-web-browser';
import { useTranslation } from 'react-i18next';
import { Trans, useTranslation } from 'react-i18next';
import { SafeAreaView } from 'react-native-safe-area-context';
import { setConsentAccepted, getConsentAccepted } from '../../src/storage/appStorage';
import { fetchLegalLinks } from '@/src/services/legalApi';
import { getOnboardingCompleted } from '@/src/storage/appStorage';
import { API_BASE_URL } from '@/src/constants/env';
// 导入 SVG 组件
import FlowersBg from '../../assets/images/index/flowers_endbg.svg';
@@ -19,11 +20,19 @@ export default function SplashScreen() {
const { t } = useTranslation();
const [showConsent, setShowConsent] = useState(false);
const [links, setLinks] = useState<{ privacy?: string; terms?: string }>({});
const [linksLoading, setLinksLoading] = useState(false);
const mountedRef = useRef(true);
useEffect(() => {
checkConsent();
}, []);
useEffect(() => {
return () => {
mountedRef.current = false;
};
}, []);
const checkConsent = async () => {
const accepted = await getConsentAccepted();
setShowConsent(!accepted);
@@ -53,23 +62,48 @@ export default function SplashScreen() {
}
};
async function refreshLegalLinks(): Promise<{ privacy?: string; terms?: string }> {
if (mountedRef.current) setLinksLoading(true);
try {
const res = await fetchLegalLinks();
const next = { privacy: res.privacyPolicyUrl, terms: res.termsOfUseUrl };
if (mountedRef.current) setLinks(next);
return next;
} catch (e) {
// 不阻塞主流程:失败时不崩溃,链接入口仍可点(会提示)
if (__DEV__) console.log('[LegalLinks] 拉取失败splash:', e);
if (mountedRef.current) setLinks({});
return {};
} finally {
if (mountedRef.current) setLinksLoading(false);
}
}
async function handleOpenLegal(type: 'privacy' | 'terms') {
const currentUrl = type === 'privacy' ? links.privacy : links.terms;
if (currentUrl) {
await openLink(currentUrl);
return;
}
// 链接还没拿到/拉取失败:点击时主动再拉一次,避免“点了没反应”
const next = await refreshLegalLinks();
const nextUrl = type === 'privacy' ? next.privacy : next.terms;
if (nextUrl) {
await openLink(nextUrl);
return;
}
const msg =
typeof __DEV__ !== 'undefined' && __DEV__
? t('consent.linkUnavailableDev', { baseUrl: API_BASE_URL })
: t('consent.linkUnavailable');
Alert.alert(t('common.notice'), msg);
}
// 拉取协议链接(由后端按语言下发;默认 EN
useEffect(() => {
let cancelled = false;
(async () => {
try {
const res = await fetchLegalLinks();
if (cancelled) return;
setLinks({ privacy: res.privacyPolicyUrl, terms: res.termsOfUseUrl });
} catch (e) {
// 不阻塞主流程:失败时不崩溃,链接入口可不展示
if (__DEV__) console.log('[LegalLinks] 拉取失败splash:', e);
if (!cancelled) setLinks({});
}
})();
return () => {
cancelled = true;
};
void refreshLegalLinks();
}, []);
const bgDecorationTop = 363;
@@ -114,23 +148,33 @@ export default function SplashScreen() {
<WelcomeBtn width={87} height={57} />
</TouchableOpacity>
<View style={styles.linksContainer}>
<TouchableOpacity
disabled={!links.privacy}
onPress={() => (links.privacy ? openLink(links.privacy) : undefined)}
>
<Text style={styles.linkText}>{t('consent.privacy')}</Text>
</TouchableOpacity>
<View style={styles.divider} />
<TouchableOpacity
disabled={!links.terms}
onPress={() => (links.terms ? openLink(links.terms) : undefined)}
>
<Text style={styles.linkText}>{t('consent.terms')}</Text>
</TouchableOpacity>
</View>
<Text style={styles.noticeText}>{t('consent.notice')}</Text>
<Text style={styles.noticeText}>
<Trans
i18nKey="consent.noticeRich"
values={{
privacyLabel: t('consent.privacy'),
termsLabel: t('consent.terms'),
privacySuffix: !links.privacy && linksLoading ? t('consent.linkLoadingSuffix') : '',
termsSuffix: !links.terms && linksLoading ? t('consent.linkLoadingSuffix') : '',
}}
components={{
privacy: (
<Text
style={[styles.noticeLinkText, !links.privacy && styles.noticeLinkTextDisabled]}
onPress={() => void handleOpenLegal('privacy')}
suppressHighlighting
/>
),
terms: (
<Text
style={[styles.noticeLinkText, !links.terms && styles.noticeLinkTextDisabled]}
onPress={() => void handleOpenLegal('terms')}
suppressHighlighting
/>
),
}}
/>
</Text>
</>
)}
</SafeAreaView>
@@ -179,10 +223,6 @@ const styles = StyleSheet.create({
buttonWrapper: {
marginBottom: 40,
},
linksContainer: {
flexDirection: 'row',
alignItems: 'center',
},
noticeText: {
marginTop: 10,
paddingHorizontal: 28,
@@ -191,15 +231,14 @@ const styles = StyleSheet.create({
textAlign: 'center',
color: 'rgba(119, 47, 0, 0.45)',
},
linkText: {
noticeLinkText: {
fontSize: 12,
color: 'rgba(119, 47, 0, 0.5)', // 使用半透明的文字颜色
// 颜色区分:协议链接更醒目
color: 'rgba(119, 47, 0, 0.75)',
textDecorationLine: 'underline',
fontWeight: '600',
},
divider: {
width: 1,
height: 12,
backgroundColor: 'rgba(119, 47, 0, 0.2)',
marginHorizontal: 15,
noticeLinkTextDisabled: {
opacity: 0.55,
},
});