AlertFilter.tsx
1 /** 2 * Alert filter component for filtering notifications by type 3 */ 4 import React from 'react'; 5 import { 6 View, 7 Text, 8 StyleSheet, 9 TouchableOpacity, 10 ScrollView, 11 } from 'react-native'; 12 import type { FilterType } from '../types/notifications'; 13 import { 14 NOTIFICATION_TYPE_COLORS, 15 NOTIFICATION_TYPE_LABELS, 16 } from '../types/notifications'; 17 import { Colors } from '../theme/colors'; 18 19 interface AlertFilterProps { 20 currentFilter: FilterType; 21 onFilterChange: (filter: FilterType) => void; 22 counts: Record<FilterType, number>; 23 } 24 25 interface FilterOption { 26 value: FilterType; 27 label: string; 28 color?: string; 29 } 30 31 const FILTER_OPTIONS: FilterOption[] = [ 32 { value: 'all', label: 'All' }, 33 { 34 value: 'governance', 35 label: NOTIFICATION_TYPE_LABELS.governance, 36 color: NOTIFICATION_TYPE_COLORS.governance, 37 }, 38 { 39 value: 'swap', 40 label: NOTIFICATION_TYPE_LABELS.swap, 41 color: NOTIFICATION_TYPE_COLORS.swap, 42 }, 43 { 44 value: 'price', 45 label: NOTIFICATION_TYPE_LABELS.price, 46 color: NOTIFICATION_TYPE_COLORS.price, 47 }, 48 { 49 value: 'system', 50 label: NOTIFICATION_TYPE_LABELS.system, 51 color: NOTIFICATION_TYPE_COLORS.system, 52 }, 53 ]; 54 55 export function AlertFilter({ 56 currentFilter, 57 onFilterChange, 58 counts, 59 }: AlertFilterProps) { 60 return ( 61 <View style={styles.container}> 62 <ScrollView 63 horizontal 64 showsHorizontalScrollIndicator={false} 65 contentContainerStyle={styles.scrollContent} 66 > 67 {FILTER_OPTIONS.map((option) => { 68 const isActive = currentFilter === option.value; 69 const count = counts[option.value] || 0; 70 71 return ( 72 <TouchableOpacity 73 key={option.value} 74 style={[ 75 styles.filterButton, 76 isActive ? styles.activeButton : null, 77 isActive && option.color ? { borderColor: option.color } : null, 78 ]} 79 onPress={() => onFilterChange(option.value)} 80 activeOpacity={0.7} 81 > 82 <Text 83 style={[ 84 styles.filterText, 85 isActive ? styles.activeText : null, 86 isActive && option.color ? { color: option.color } : null, 87 ]} 88 > 89 {option.label} 90 </Text> 91 {count > 0 && ( 92 <View 93 style={[ 94 styles.countBadge, 95 isActive && option.color 96 ? { backgroundColor: option.color } 97 : null, 98 ]} 99 > 100 <Text style={styles.countText}>{count}</Text> 101 </View> 102 )} 103 </TouchableOpacity> 104 ); 105 })} 106 </ScrollView> 107 </View> 108 ); 109 } 110 111 const styles = StyleSheet.create({ 112 container: { 113 paddingVertical: 12, 114 borderBottomWidth: 1, 115 borderBottomColor: Colors.border.default, 116 }, 117 scrollContent: { 118 paddingHorizontal: 12, 119 gap: 8, 120 }, 121 filterButton: { 122 flexDirection: 'row', 123 alignItems: 'center', 124 paddingHorizontal: 14, 125 paddingVertical: 8, 126 borderRadius: 20, 127 backgroundColor: Colors.background.secondary, 128 borderWidth: 1, 129 borderColor: Colors.border.strong, 130 marginHorizontal: 4, 131 }, 132 activeButton: { 133 backgroundColor: Colors.background.tertiary, 134 borderColor: Colors.accent.alpha, 135 }, 136 filterText: { 137 color: Colors.text.secondary, 138 fontSize: 14, 139 fontWeight: '500', 140 }, 141 activeText: { 142 color: Colors.accent.alpha, 143 }, 144 countBadge: { 145 marginLeft: 6, 146 backgroundColor: Colors.border.strong, 147 borderRadius: 10, 148 minWidth: 20, 149 height: 20, 150 justifyContent: 'center', 151 alignItems: 'center', 152 paddingHorizontal: 6, 153 }, 154 countText: { 155 color: Colors.text.primary, 156 fontSize: 11, 157 fontWeight: 'bold', 158 }, 159 });