feat(vip): 限制底部栏自定义功能为VIP专享

非VIP用户尝试配置底部栏时将显示会员购买弹窗,
只有VIP会员才能自由开启或关闭导航标签。
包含会员权益说明的国际化支持和存储结构重构。
This commit is contained in:
richarjiang
2025-12-01 16:56:54 +08:00
parent a47f0fb72e
commit be0dd750eb
7 changed files with 106 additions and 23 deletions

View File

@@ -1,5 +1,6 @@
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding';
import { useVipService } from '@/hooks/useVipService';
import {
resetToDefault,
selectTabBarConfigs,
@@ -9,7 +10,7 @@ import {
import { Ionicons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import { useRouter } from 'expo-router';
import React, { useCallback } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import {
Alert,
ScrollView,
@@ -20,6 +21,7 @@ import {
View
} from 'react-native';
import { MembershipModal } from '@/components/model/MembershipModal';
import { HeaderBar } from '@/components/ui/HeaderBar';
import { IconSymbol } from '@/components/ui/IconSymbol';
import { palette } from '@/constants/Colors';
@@ -31,15 +33,38 @@ export default function TabBarConfigScreen() {
const dispatch = useAppDispatch();
const safeAreaTop = useSafeAreaTop(60);
const configs = useAppSelector(selectTabBarConfigs);
const { isVip } = useVipService();
const [showMembershipModal, setShowMembershipModal] = useState(false);
// 处理开关切换
const handleToggle = useCallback(
(tabId: string) => {
dispatch(toggleTabEnabled(tabId));
// 直接检查用户是否是 VIP底部栏配置不是权益类功能而是基础功能
if (isVip) {
// VIP 用户可以正常切换
dispatch(toggleTabEnabled(tabId));
} else {
// 非 VIP 用户显示购买弹窗
setShowMembershipModal(true);
}
},
[dispatch]
[dispatch, isVip]
);
// 页面加载时检查 VIP 状态
useEffect(() => {
if (!isVip) {
// 非 VIP 用户进入页面时立即显示购买弹窗
setShowMembershipModal(true);
}
}, [isVip]);
// 购买成功回调
const handlePurchaseSuccess = useCallback(() => {
// 购买成功后可以执行一些操作,比如刷新用户信息
console.log('会员购买成功');
}, []);
// 恢复默认设置
const handleReset = useCallback(() => {
Alert.alert(
@@ -80,6 +105,11 @@ export default function TabBarConfigScreen() {
{t('personal.tabBarConfig.cannotDisable')}
</Text>
)}
{item.canBeDisabled && !isVip && (
<Text style={styles.vipSubtitle}>
{t('personal.tabBarConfig.vipOnly')}
</Text>
)}
</View>
</View>
@@ -87,7 +117,7 @@ export default function TabBarConfigScreen() {
<Switch
value={item.enabled}
onValueChange={() => handleToggle(item.id)}
disabled={!item.canBeDisabled}
disabled={!item.canBeDisabled || !isVip}
trackColor={{ false: '#E5E5E5', true: '#9370DB' }}
thumbColor="#FFFFFF"
style={styles.switch}
@@ -153,6 +183,13 @@ export default function TabBarConfigScreen() {
</View>
</ScrollView>
{/* 会员购买弹窗 */}
<MembershipModal
visible={showMembershipModal}
onClose={() => setShowMembershipModal(false)}
onPurchaseSuccess={handlePurchaseSuccess}
/>
</View>
);
}
@@ -253,6 +290,10 @@ const styles = StyleSheet.create({
fontSize: 12,
color: '#9370DB',
},
vipSubtitle: {
fontSize: 12,
color: '#FF6B6B',
},
switch: {
transform: [{ scaleX: 0.9 }, { scaleY: 0.9 }],
},