expo-popcore-app/components/message/MessageTabBar.tsx

162 lines
3.8 KiB
TypeScript

import React from 'react'
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
import { LinearGradient } from 'expo-linear-gradient'
// Types
export type MessageType = 'ACTIVITY' | 'SYSTEM' | 'BILLING' | undefined
export interface TabItem {
key: string
label: string
type: MessageType
}
export interface MessageTabBarProps {
activeTab: MessageType
onTabChange: (type: MessageType) => void
unreadCounts?: {
all?: number
activity?: number
system?: number
billing?: number
}
}
// Constants
export const TAB_ITEMS: TabItem[] = [
{ key: 'all', label: '全部', type: undefined },
{ key: 'activity', label: '互动', type: 'ACTIVITY' },
{ key: 'system', label: '系统', type: 'SYSTEM' },
{ key: 'billing', label: '账单', type: 'BILLING' },
]
// Helper function to format badge count
const formatBadgeCount = (count: number): string => {
if (count > 99) {
return '99+'
}
return String(count)
}
// Helper function to get unread count for a tab
const getUnreadCount = (
key: string,
unreadCounts?: MessageTabBarProps['unreadCounts']
): number | undefined => {
if (!unreadCounts) return undefined
switch (key) {
case 'all':
return unreadCounts.all
case 'activity':
return unreadCounts.activity
case 'system':
return unreadCounts.system
case 'billing':
return unreadCounts.billing
default:
return undefined
}
}
export const MessageTabBar: React.FC<MessageTabBarProps> = ({
activeTab,
onTabChange,
unreadCounts,
}) => {
return (
<View style={styles.container}>
{TAB_ITEMS.map((tab) => {
const isActive = activeTab === tab.type
const unreadCount = getUnreadCount(tab.key, unreadCounts)
const showBadge = unreadCount !== undefined && unreadCount > 0
return (
<TouchableOpacity
key={tab.key}
testID={`tab-${tab.key}`}
style={styles.tabItem}
onPress={() => onTabChange(tab.type)}
activeOpacity={0.7}
>
<View style={styles.tabContent}>
<Text
style={[
styles.tabLabel,
isActive ? styles.tabLabelActive : styles.tabLabelInactive,
]}
>
{tab.label}
</Text>
{showBadge && (
<View testID={`tab-${tab.key}-badge`} style={styles.badge}>
<Text style={styles.badgeText}>
{formatBadgeCount(unreadCount)}
</Text>
</View>
)}
</View>
{isActive && (
<LinearGradient
testID={`tab-${tab.key}-active-indicator`}
colors={['#FF9966', '#FF6699', '#9966FF']}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.activeIndicator}
/>
)}
</TouchableOpacity>
)
})}
</View>
)
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
backgroundColor: '#090A0B',
paddingHorizontal: 16,
paddingTop: 12,
},
tabItem: {
marginRight: 24,
paddingBottom: 8,
alignItems: 'center',
},
tabContent: {
flexDirection: 'row',
alignItems: 'center',
},
tabLabel: {
fontSize: 16,
fontWeight: '500',
},
tabLabelActive: {
color: '#FFFFFF',
},
tabLabelInactive: {
color: '#8A8A8A',
},
activeIndicator: {
height: 2,
width: '100%',
marginTop: 6,
borderRadius: 1,
},
badge: {
backgroundColor: '#FF3B30',
borderRadius: 10,
minWidth: 18,
height: 18,
paddingHorizontal: 5,
marginLeft: 4,
justifyContent: 'center',
alignItems: 'center',
},
badgeText: {
color: '#FFFFFF',
fontSize: 11,
fontWeight: '600',
},
})