react-native-debug-toolkit
Version:
A simple yet powerful debugging toolkit for React Native with a convenient floating UI for development
318 lines (303 loc) • 7.8 kB
JavaScript
import React, { useState } from 'react'
import {
View,
Text,
StyleSheet,
FlatList,
TouchableOpacity,
} from 'react-native'
import TrackLogDetails from './TrackLogDetails'
const SubViewTrackLogs = ({ logs = [] }) => {
const [selectedLog, setSelectedLog] = useState(null)
const getEventColor = (eventName) => {
if (eventName?.includes('error')) return '#ff4444'
if (eventName?.includes('click')) return '#4CAF50'
if (eventName?.includes('view')) return '#2196F3'
if (eventName?.includes('search')) return '#FF9800'
return '#9C27B0'
}
const getTimeAgo = (timestamp) => {
const now = new Date()
const eventTime = new Date(timestamp)
const diffMs = now - eventTime
const diffSeconds = Math.floor(diffMs / 1000)
const diffMinutes = Math.floor(diffSeconds / 60)
const diffHours = Math.floor(diffMinutes / 60)
if (diffSeconds < 60) {
return `${diffSeconds}s ago`
} else if (diffMinutes < 60) {
return `${diffMinutes}m ago`
} else if (diffHours < 24) {
return `${diffHours}h ago`
} else {
const diffDays = Math.floor(diffHours / 24)
return `${diffDays}d ago`
}
}
const renderLogItem = ({ item }) => {
const eventColor = getEventColor(item.eventName)
return (
<TouchableOpacity
style={styles.logItem}
onPress={() => setSelectedLog(item)}>
<View style={styles.logItemContainer}>
<View
style={[styles.eventIndicator, { backgroundColor: eventColor }]}
/>
<View style={styles.logContent}>
<View style={styles.eventRow}>
<Text style={[styles.eventName, { color: eventColor }]}>
{item.eventName || 'Unknown Event'}
</Text>
{item.entityType && (
<Text style={styles.entityType}>
{item.entityType}
</Text>
)}
</View>
{item.entityName && (
<Text style={styles.entityName} numberOfLines={1}>
{item.entityName}
</Text>
)}
{item.frontOperation && (
<Text style={styles.operation} numberOfLines={1}>
Operation: {item.frontOperation}
</Text>
)}
<View style={styles.logFooter}>
<Text style={styles.time}>
{item.timestamp
? getTimeAgo(item.timestamp)
: 'Unknown time'}
</Text>
<View style={styles.additionalInfo}>
{item.pageId && (
<Text style={styles.pageId} numberOfLines={1}>
Page: {item.pageId}
</Text>
)}
{item.position && (
<Text style={styles.position}>
Pos: {item.position}
</Text>
)}
</View>
</View>
</View>
</View>
</TouchableOpacity>
)
}
// If a log is selected, show the details view with a back button
if (selectedLog) {
return (
<View style={styles.container}>
<View style={styles.detailsHeader}>
<TouchableOpacity
style={styles.backButton}
onPress={() => setSelectedLog(null)}>
<Text style={styles.backButtonText}>← Back</Text>
</TouchableOpacity>
<View style={styles.headerEventInfo}>
<Text
style={[
styles.headerEvent,
{ color: getEventColor(selectedLog.eventName) },
]}>
{selectedLog.eventName || 'Unknown Event'}
</Text>
{selectedLog.entityType && (
<Text style={styles.headerEntityType}>
{selectedLog.entityType}
</Text>
)}
</View>
</View>
<TrackLogDetails log={selectedLog} />
</View>
)
}
// Otherwise show the list view
return (
<View style={styles.container}>
{logs.length === 0 ? (
<View style={styles.emptyContainer}>
<Text style={styles.emptyText}>No track events logged yet</Text>
<Text style={styles.emptySubtext}>
Track events will appear here as they occur during development
</Text>
</View>
) : (
<>
<View style={styles.statsContainer}>
<Text style={styles.statsText}>
{logs.length} events logged
</Text>
</View>
<FlatList
data={[...logs].sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))}
renderItem={renderLogItem}
keyExtractor={(item, index) => `${item.timestamp}-${index}`}
style={styles.list}
showsVerticalScrollIndicator={true}
/>
</>
)}
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
list: {
flex: 1,
},
emptyContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 40,
},
emptyText: {
textAlign: 'center',
color: '#666',
fontSize: 16,
fontWeight: '500',
marginBottom: 8,
},
emptySubtext: {
textAlign: 'center',
color: '#999',
fontSize: 14,
},
statsContainer: {
padding: 12,
borderBottomWidth: 1,
borderBottomColor: '#eee',
backgroundColor: '#f8f9fa',
},
statsText: {
fontSize: 12,
color: '#666',
fontWeight: '500',
},
logItem: {
borderBottomWidth: 1,
borderBottomColor: '#eee',
},
logItemContainer: {
flexDirection: 'row',
padding: 12,
},
eventIndicator: {
width: 4,
borderRadius: 2,
marginRight: 12,
},
logContent: {
flex: 1,
},
eventRow: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 4,
},
eventName: {
fontSize: 15,
fontWeight: 'bold',
marginRight: 8,
},
entityType: {
fontSize: 11,
backgroundColor: '#f0f0f0',
color: '#666',
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 6,
fontWeight: '500',
},
entityName: {
fontSize: 14,
color: '#333',
marginBottom: 4,
fontWeight: '500',
},
operation: {
fontSize: 13,
color: '#666',
marginBottom: 6,
fontStyle: 'italic',
},
logFooter: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-end',
},
time: {
fontSize: 12,
color: '#999',
},
additionalInfo: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
pageId: {
fontSize: 11,
color: '#666',
backgroundColor: '#f8f9fa',
paddingHorizontal: 4,
paddingVertical: 1,
borderRadius: 3,
maxWidth: 80,
},
position: {
fontSize: 11,
color: '#666',
backgroundColor: '#f8f9fa',
paddingHorizontal: 4,
paddingVertical: 1,
borderRadius: 3,
},
detailsHeader: {
flexDirection: 'row',
alignItems: 'center',
padding: 15,
borderBottomWidth: 1,
borderBottomColor: '#eee',
backgroundColor: '#f8f9fa',
},
backButton: {
paddingHorizontal: 10,
paddingVertical: 5,
borderRadius: 4,
backgroundColor: '#eee',
marginRight: 10,
},
backButtonText: {
color: '#333',
fontWeight: '500',
},
headerEventInfo: {
flexDirection: 'row',
alignItems: 'center',
},
headerEvent: {
fontSize: 16,
fontWeight: 'bold',
marginRight: 10,
},
headerEntityType: {
fontSize: 12,
backgroundColor: '#f0f0f0',
color: '#666',
paddingHorizontal: 8,
paddingVertical: 3,
borderRadius: 8,
fontWeight: '500',
},
})
export default SubViewTrackLogs