Files
rn-app/components/Header/index.tsx
2025-11-13 16:47:10 +08:00

168 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Header 组件 - 增强版
* 基于 xinyong-web 的 header 组件重建
* 功能包括:
* - 顶部导航栏logo、搜索、用户按钮
* - 左侧菜单(侧边栏)
* - 登录/注册弹窗
* - 钱包信息显示
* - 主题适配
*/
import React, { useState, useCallback, useMemo } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
TextInput,
Image,
Dimensions,
Modal,
ScrollView,
SafeAreaView,
} from 'react-native';
import { useColorScheme, useThemeColors } from '@/theme';
import { useIsLoggedIn, useUser } from '@/stores/userStore';
import { useLogo } from '@/stores/tenantStore';
import { Ionicons, AntDesign } from '@expo/vector-icons';
import LeftMenu from './LeftMenu';
import LoginRegisterModal from './LoginRegisterModal';
import WalletAmount from '../WalletAmount';
import { styles } from './styles';
const { width } = Dimensions.get('window');
interface HeaderProps {
onSearch?: (keyword: string) => void;
onMessagePress?: () => void;
onMenuPress?: () => void;
unreadCount?: number;
}
/**
* Header 组件 - 增强版
*/
export default function Header({
onSearch,
onMessagePress,
onMenuPress,
unreadCount = 0,
}: HeaderProps) {
const colorScheme = useColorScheme();
const s = styles[colorScheme];
const themeColors = useThemeColors();
const isLoggedIn = useIsLoggedIn();
const user = useUser();
const logoUrl = useLogo();
const [searchText, setSearchText] = useState('');
const [showLeftMenu, setShowLeftMenu] = useState(false);
const [showLoginModal, setShowLoginModal] = useState(false);
const handleSearch = useCallback(() => {
if (searchText.trim()) {
onSearch?.(searchText);
setSearchText('');
}
}, [searchText, onSearch]);
const handleMenuPress = useCallback(() => {
setShowLeftMenu(true);
onMenuPress?.();
}, [onMenuPress]);
const handleLoginPress = useCallback(() => {
setShowLoginModal(true);
}, []);
return (
<>
<View style={s.container}>
{/* 左侧部分 */}
<View style={s.leftSection}>
{/* 菜单按钮 */}
<TouchableOpacity style={s.menuButton} onPress={handleMenuPress} activeOpacity={0.7}>
<AntDesign name="menu-unfold" size={22} color={themeColors.text} />
</TouchableOpacity>
{/* Logo */}
{logoUrl ? <Image source={{ uri: logoUrl }} style={s.logoImage} /> : null}
</View>
{/* 搜索框 */}
{/*<View style={s.searchContainer}>*/}
{/* <Ionicons name="search" size={16} color={themeColors.text + '60'} />*/}
{/* <TextInput*/}
{/* style={s.searchInput}*/}
{/* placeholder="搜索游戏..."*/}
{/* placeholderTextColor={themeColors.text + '60'}*/}
{/* value={searchText}*/}
{/* onChangeText={setSearchText}*/}
{/* onSubmitEditing={handleSearch}*/}
{/* returnKeyType="search"*/}
{/* />*/}
{/* {searchText ? (*/}
{/* <TouchableOpacity onPress={() => setSearchText('')}>*/}
{/* <Ionicons name="close" size={16} color={themeColors.text} />*/}
{/* </TouchableOpacity>*/}
{/* ) : null}*/}
{/*</View>*/}
{/* 右侧部分 */}
<View style={s.rightSection}>
{isLoggedIn && user ? (
<>
{/* 消息按钮 */}
<TouchableOpacity style={s.iconButton} onPress={onMessagePress} activeOpacity={0.7}>
<Ionicons name="chatbubble-outline" size={20} color={themeColors.text} />
{unreadCount > 0 && (
<View style={s.badge}>
<Text style={s.badgeText}>{unreadCount > 99 ? '99+' : unreadCount}</Text>
</View>
)}
</TouchableOpacity>
{/* 用户头像 */}
<TouchableOpacity style={s.iconButton} activeOpacity={0.7}>
{user.avatar ? (
<Image
source={{ uri: user.avatar }}
style={{ width: 32, height: 32, borderRadius: 16 }}
/>
) : (
<Ionicons name="person-circle" size={24} color={themeColors.primary} />
)}
</TouchableOpacity>
</>
) : (
/* 登录/注册按钮 */
<View style={s.authButtons}>
<TouchableOpacity
style={[s.authButton, s.registerButton]}
onPress={() => setShowLoginModal(true)}
activeOpacity={0.7}
>
<Text style={s.registerButtonText}></Text>
</TouchableOpacity>
<TouchableOpacity
style={[s.authButton, s.loginButton]}
onPress={() => setShowLoginModal(true)}
activeOpacity={0.7}
>
<Text style={s.loginButtonText}></Text>
</TouchableOpacity>
</View>
)}
</View>
</View>
{/* 左侧菜单 */}
<LeftMenu visible={showLeftMenu} onClose={() => setShowLeftMenu(false)} />
{/* 登录/注册弹窗 */}
<LoginRegisterModal visible={showLoginModal} onClose={() => setShowLoginModal(false)} />
</>
);
}