A React Native app for the ultimate thinking partner.
at sdk-v1-upgrade 222 lines 5.9 kB view raw
1import React from 'react'; 2import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; 3import { darkTheme } from '../theme'; 4import { Ionicons } from '@expo/vector-icons'; 5import { LettaAgent } from '../types/letta'; 6 7interface AgentCardProps { 8 agent: LettaAgent; 9 isSelected: boolean; 10 onPress: () => void; 11 isFavorited?: boolean; 12 onToggleFavorite?: () => void; 13} 14 15const AgentCard: React.FC<AgentCardProps> = ({ agent, isSelected, onPress, isFavorited, onToggleFavorite }) => { 16 const formatDate = (dateString: string) => { 17 const date = new Date(dateString); 18 return date.toLocaleDateString('en-US', { 19 month: 'short', 20 day: 'numeric', 21 }); 22 }; 23 24 return ( 25 <TouchableOpacity 26 style={[styles.container, isSelected && styles.selectedContainer]} 27 onPress={onPress} 28 activeOpacity={0.7} 29 > 30 <View style={styles.content}> 31 <View style={styles.header}> 32 <View style={styles.avatarContainer}> 33 <Ionicons 34 name="person-outline" 35 size={20} 36 color={isSelected ? darkTheme.colors.text.inverse : darkTheme.colors.interactive.primary} 37 /> 38 </View> 39 <View style={styles.textContainer}> 40 <View style={styles.rowHeader}> 41 <Text 42 style={[styles.name, isSelected && styles.selectedText]} 43 numberOfLines={1} 44 > 45 {agent.name} 46 </Text> 47 {onToggleFavorite && ( 48 <TouchableOpacity 49 accessibilityLabel={isFavorited ? 'Unfavorite agent' : 'Favorite agent'} 50 onPress={onToggleFavorite} 51 style={styles.starBtn} 52 > 53 <Ionicons name={isFavorited ? 'star' : 'star-outline'} size={16} color={isFavorited ? '#ffd166' : (isSelected ? darkTheme.colors.text.inverse : darkTheme.colors.text.secondary)} /> 54 </TouchableOpacity> 55 )} 56 </View> 57 <Text 58 style={[styles.date, isSelected && styles.selectedSubtext]} 59 > 60 Created {formatDate(agent.created_at)} 61 </Text> 62 </View> 63 </View> 64 65 {agent.description && ( 66 <Text 67 style={[styles.description, isSelected && styles.selectedSubtext]} 68 numberOfLines={2} 69 > 70 {agent.description} 71 </Text> 72 )} 73 74 {agent.tags && agent.tags.length > 0 && ( 75 <View style={styles.tagsContainer}> 76 {agent.tags.slice(0, 3).map((tag, index) => ( 77 <View 78 key={index} 79 style={[styles.tag, isSelected && styles.selectedTag]} 80 > 81 <Text 82 style={[styles.tagText, isSelected && styles.selectedTagText]} 83 > 84 {tag} 85 </Text> 86 </View> 87 ))} 88 {agent.tags.length > 3 && ( 89 <Text style={[styles.moreText, isSelected && styles.selectedSubtext]}> 90 +{agent.tags.length - 3} more 91 </Text> 92 )} 93 </View> 94 )} 95 </View> 96 97 {isSelected && ( 98 <View style={styles.selectedIndicator}> 99 <Ionicons name="checkmark" size={16} color={darkTheme.colors.text.inverse} /> 100 </View> 101 )} 102 </TouchableOpacity> 103 ); 104}; 105 106const styles = StyleSheet.create({ 107 container: { 108 marginHorizontal: 16, 109 marginVertical: 6, 110 padding: 16, 111 backgroundColor: darkTheme.colors.background.tertiary, 112 borderRadius: 12, 113 borderWidth: 1, 114 borderColor: darkTheme.colors.border.primary, 115 elevation: 1, 116 shadowColor: '#000', 117 shadowOffset: { 118 width: 0, 119 height: 1, 120 }, 121 shadowOpacity: 0.1, 122 shadowRadius: 2, 123 }, 124 selectedContainer: { 125 backgroundColor: darkTheme.colors.interactive.primary, 126 borderColor: darkTheme.colors.interactive.primary, 127 }, 128 content: { 129 flex: 1, 130 }, 131 header: { 132 flexDirection: 'row', 133 alignItems: 'center', 134 marginBottom: 8, 135 }, 136 rowHeader: { 137 flexDirection: 'row', 138 alignItems: 'center', 139 justifyContent: 'space-between', 140 }, 141 avatarContainer: { 142 width: 40, 143 height: 40, 144 borderRadius: 20, 145 backgroundColor: darkTheme.colors.background.surface, 146 alignItems: 'center', 147 justifyContent: 'center', 148 marginRight: 12, 149 }, 150 textContainer: { 151 flex: 1, 152 }, 153 name: { 154 fontSize: 16, 155 fontWeight: '600', 156 color: darkTheme.colors.text.primary, 157 marginBottom: 2, 158 }, 159 starBtn: { 160 paddingHorizontal: 6, 161 paddingVertical: 4, 162 marginLeft: 8, 163 }, 164 selectedText: { 165 color: darkTheme.colors.text.inverse, 166 }, 167 date: { 168 fontSize: 12, 169 color: darkTheme.colors.text.secondary, 170 }, 171 selectedSubtext: { 172 color: 'rgba(255, 255, 255, 0.8)', 173 }, 174 description: { 175 fontSize: 14, 176 color: darkTheme.colors.text.secondary, 177 lineHeight: 18, 178 marginBottom: 8, 179 }, 180 tagsContainer: { 181 flexDirection: 'row', 182 alignItems: 'center', 183 flexWrap: 'wrap', 184 }, 185 tag: { 186 backgroundColor: darkTheme.colors.background.surface, 187 borderRadius: 12, 188 paddingHorizontal: 8, 189 paddingVertical: 4, 190 marginRight: 6, 191 marginBottom: 4, 192 }, 193 selectedTag: { 194 backgroundColor: 'rgba(255, 255, 255, 0.2)', 195 }, 196 tagText: { 197 fontSize: 11, 198 color: darkTheme.colors.interactive.primary, 199 fontWeight: '500', 200 }, 201 selectedTagText: { 202 color: darkTheme.colors.text.inverse, 203 }, 204 moreText: { 205 fontSize: 11, 206 color: darkTheme.colors.text.secondary, 207 fontStyle: 'italic', 208 }, 209 selectedIndicator: { 210 position: 'absolute', 211 top: 12, 212 right: 12, 213 width: 24, 214 height: 24, 215 borderRadius: 12, 216 backgroundColor: 'rgba(255, 255, 255, 0.2)', 217 alignItems: 'center', 218 justifyContent: 'center', 219 }, 220}); 221 222export default AgentCard;