297 lines
7.2 KiB
TypeScript
297 lines
7.2 KiB
TypeScript
/**
|
||
* 左侧菜单组件
|
||
* 基于 react-native-paper Drawer 组件重建
|
||
* 功能包括:
|
||
* - 用户钱包信息
|
||
* - 菜单项导航
|
||
* - 利息宝显示
|
||
* - 登录状态判断
|
||
*/
|
||
|
||
import React, { useState, useCallback, useMemo } from 'react';
|
||
import { View, Text, ScrollView, Modal, TouchableOpacity, Dimensions } from 'react-native';
|
||
import { Drawer, Button, Divider } from 'react-native-paper';
|
||
import { useColorScheme, useThemeColors } from '@/theme';
|
||
import { createThemeStyles } from '@/theme';
|
||
import { useIsLoggedIn, useUser } from '@/stores';
|
||
import Ionicons from '@expo/vector-icons/Ionicons';
|
||
import WalletAmount from '../WalletAmount';
|
||
|
||
const { width } = Dimensions.get('window');
|
||
|
||
/**
|
||
* 创建主题样式
|
||
*/
|
||
const styles = createThemeStyles((colors) => ({
|
||
overlay: {
|
||
flex: 1,
|
||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||
},
|
||
drawerContainer: {
|
||
flex: 1,
|
||
backgroundColor: colors.background,
|
||
width: width * 0.65,
|
||
position: 'absolute',
|
||
top: 0,
|
||
left: 0,
|
||
right: 0,
|
||
bottom: 0,
|
||
},
|
||
container: {
|
||
flex: 1,
|
||
backgroundColor: colors.background,
|
||
},
|
||
walletSection: {
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 16,
|
||
backgroundColor: colors.card,
|
||
marginHorizontal: 12,
|
||
marginVertical: 12,
|
||
borderRadius: 12,
|
||
},
|
||
walletLabel: {
|
||
fontSize: 12,
|
||
color: colors.text + '80',
|
||
marginBottom: 8,
|
||
},
|
||
walletButtons: {
|
||
flexDirection: 'row',
|
||
gap: 8,
|
||
marginTop: 12,
|
||
},
|
||
buttonText: {
|
||
fontSize: 12,
|
||
fontWeight: '600',
|
||
},
|
||
lixibaoSection: {
|
||
marginHorizontal: 12,
|
||
marginVertical: 12,
|
||
paddingHorizontal: 12,
|
||
paddingVertical: 12,
|
||
borderRadius: 12,
|
||
borderWidth: 2,
|
||
borderColor: colors.primary,
|
||
backgroundColor: colors.card,
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
},
|
||
lixibaoLeft: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
flex: 1,
|
||
},
|
||
lixibaoInfo: {
|
||
flex: 1,
|
||
},
|
||
lixibaoLabel: {
|
||
fontSize: 12,
|
||
color: colors.text + '80',
|
||
},
|
||
lixibaoValue: {
|
||
fontSize: 14,
|
||
fontWeight: '700',
|
||
color: colors.primary,
|
||
marginTop: 4,
|
||
},
|
||
emptyText: {
|
||
textAlign: 'center',
|
||
fontSize: 14,
|
||
color: colors.text + '80',
|
||
paddingVertical: 40,
|
||
},
|
||
}));
|
||
|
||
interface LeftMenuProps {
|
||
visible: boolean;
|
||
onClose: () => void;
|
||
}
|
||
|
||
interface MenuItem {
|
||
id: string;
|
||
title: string;
|
||
icon: string;
|
||
route?: string;
|
||
requireLogin?: boolean;
|
||
}
|
||
|
||
/**
|
||
* 左侧菜单组件
|
||
*/
|
||
export default function LeftMenu({ visible, onClose }: LeftMenuProps) {
|
||
const colorScheme = useColorScheme();
|
||
const s = styles[colorScheme];
|
||
const themeColors = useThemeColors();
|
||
const isLoggedIn = useIsLoggedIn();
|
||
const user = useUser();
|
||
|
||
const [walletBalance] = useState(0); // 从 store 获取
|
||
const [interestBalance] = useState(0); // 从 store 获取
|
||
|
||
// 菜单项配置
|
||
const menuItems: MenuItem[] = useMemo(
|
||
() => [
|
||
{ id: 'balance', title: '利息宝', icon: 'gift' },
|
||
{
|
||
id: 'services',
|
||
title: '客服',
|
||
icon: 'headset',
|
||
route: '/services',
|
||
},
|
||
{
|
||
id: 'collect',
|
||
title: '收藏',
|
||
icon: 'star',
|
||
route: '/collect',
|
||
},
|
||
{
|
||
id: 'recent',
|
||
title: '最近',
|
||
icon: 'time',
|
||
route: '/recent',
|
||
},
|
||
{
|
||
id: 'betRecord',
|
||
title: '投注记录',
|
||
icon: 'document-text',
|
||
route: '/betRecord',
|
||
requireLogin: true,
|
||
},
|
||
{
|
||
id: 'activity',
|
||
title: '任务中心',
|
||
icon: 'checkmark-circle',
|
||
route: '/activity',
|
||
},
|
||
{
|
||
id: 'bonus',
|
||
title: '福利中心',
|
||
icon: 'gift',
|
||
route: '/bonus',
|
||
},
|
||
{
|
||
id: 'rebate',
|
||
title: '自助返水',
|
||
icon: 'cash',
|
||
route: '/rebate',
|
||
},
|
||
{
|
||
id: 'findBalance',
|
||
title: '找回余额',
|
||
icon: 'search',
|
||
route: '/findBalance',
|
||
},
|
||
{
|
||
id: 'message',
|
||
title: '消息中心',
|
||
icon: 'mail',
|
||
route: '/message',
|
||
},
|
||
{
|
||
id: 'promotion',
|
||
title: '推广赚钱',
|
||
icon: 'share-social',
|
||
route: '/promotion',
|
||
},
|
||
{
|
||
id: 'backup',
|
||
title: '备用网站',
|
||
icon: 'link',
|
||
route: '/backup',
|
||
},
|
||
],
|
||
[]
|
||
);
|
||
|
||
const handleMenuItemPress = useCallback(
|
||
(item: MenuItem) => {
|
||
if (item.requireLogin && !isLoggedIn) {
|
||
// 显示登录提示
|
||
return;
|
||
}
|
||
// 导航到对应页面
|
||
console.log('Navigate to:', item.route);
|
||
onClose();
|
||
},
|
||
[isLoggedIn, onClose]
|
||
);
|
||
|
||
const handleDeposit = useCallback(() => {
|
||
console.log('Navigate to deposit');
|
||
onClose();
|
||
}, [onClose]);
|
||
|
||
const handleWithdraw = useCallback(() => {
|
||
console.log('Navigate to withdraw');
|
||
onClose();
|
||
}, [onClose]);
|
||
|
||
return (
|
||
<Modal visible={visible} transparent animationType="fade" onRequestClose={onClose}>
|
||
<View style={s.overlay}>
|
||
<TouchableOpacity style={{ flex: 1 }} activeOpacity={1} onPress={onClose} />
|
||
<View style={s.drawerContainer}>
|
||
<ScrollView showsVerticalScrollIndicator={false}>
|
||
{/* 用户信息或登录提示 */}
|
||
{isLoggedIn && user ? (
|
||
<>
|
||
{/* 钱包信息 */}
|
||
<View style={s.walletSection}>
|
||
<Text style={s.walletLabel}>钱包余额</Text>
|
||
<WalletAmount balance={walletBalance} />
|
||
<View style={s.walletButtons}>
|
||
<Button
|
||
mode="contained"
|
||
onPress={handleDeposit}
|
||
style={{ flex: 1 }}
|
||
labelStyle={s.buttonText}
|
||
>
|
||
充值
|
||
</Button>
|
||
<Button
|
||
mode="outlined"
|
||
onPress={handleWithdraw}
|
||
style={{ flex: 1 }}
|
||
labelStyle={s.buttonText}
|
||
>
|
||
提现
|
||
</Button>
|
||
</View>
|
||
</View>
|
||
</>
|
||
) : (
|
||
<Text style={s.emptyText}>加入我们,开启畅赢人生!</Text>
|
||
)}
|
||
|
||
<Divider style={{ marginVertical: 8 }} />
|
||
|
||
{/* 菜单项 */}
|
||
<Drawer.Section title="">
|
||
{menuItems.map((item) => (
|
||
<Drawer.Item
|
||
key={item.id}
|
||
label={item.title}
|
||
icon={({ color, size }) => (
|
||
<Ionicons name={item.icon as any} size={size} color={color} />
|
||
)}
|
||
onPress={() => handleMenuItemPress(item)}
|
||
active={false}
|
||
right={() => (
|
||
<Ionicons
|
||
name="chevron-forward"
|
||
size={20}
|
||
color={themeColors.text + '60'}
|
||
style={{ marginRight: -10 }}
|
||
/>
|
||
)}
|
||
style={{ marginHorizontal: 0 }}
|
||
/>
|
||
))}
|
||
</Drawer.Section>
|
||
</ScrollView>
|
||
</View>
|
||
</View>
|
||
</Modal>
|
||
);
|
||
}
|