Files
boc/iom/quixzoom-app/src/components/EvidencePanel.js
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- Add NFC ePassport roadmap (ICAO 9303, eIDAS)
- Add TensorFlow.js edge face detection (BlazeFace)
- Add structured audit logger (GDPR-compliant)
- Risk scoring support

Part of KYC Apple Native UX v1.1.0
2026-06-29 16:24:48 +00:00

156 lines
4.4 KiB
JavaScript

/**
* EvidencePanel Component
* Displays extracted evidence from image analysis
*/
import React from 'react';
import {
View,
Text,
StyleSheet,
ScrollView,
Animated,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
export default function EvidencePanel({ evidence, confidence }) {
if (!evidence) return null;
const fadeAnim = new Animated.Value(0);
React.useEffect(() => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 500,
useNativeDriver: true,
}).start();
}, [evidence]);
const renderEvidenceLayer = (icon, title, items, color) => (
<View style={[styles.layerCard, { borderLeftColor: color }]}>
<View style={styles.layerHeader}>
<Icon name={icon} size={20} color={color} />
<Text style={[styles.layerTitle, { color }]}>{title}</Text>
<Text style={styles.layerCount}>{items?.length || 0}</Text>
</View>
{items && items.map((item, index) => (
<Text key={index} style={styles.layerItem}> {item}</Text>
))}
</View>
);
return (
<Animated.View style={[styles.container, { opacity: fadeAnim }]}>
<ScrollView style={styles.scrollView}>
{/* Confidence Header */}
<View style={styles.confidenceHeader}>
<Text style={styles.confidenceTitle}>Evidence Analysis</Text>
<View style={styles.confidenceBadge}>
<Text style={styles.confidenceText}>
{(confidence * 100).toFixed(0)}% confidence
</Text>
</View>
</View>
{/* Evidence Layers */}
{renderEvidenceLayer('camera-alt', 'Metadata',
evidence.metadata ? [
`GPS: ${evidence.metadata.latitude?.toFixed(6)}, ${evidence.metadata.longitude?.toFixed(6)}`,
`Accuracy: ±${evidence.metadata.accuracy?.toFixed(0)}m`,
`Device: ${evidence.metadata.device_model}`,
] : [], '#007AFF')}
{renderEvidenceLayer('visibility', 'Visual Objects',
evidence.visual_objects?.map(obj => `${obj.label} (${(obj.confidence * 100).toFixed(0)}%)`), '#34C759')}
{renderEvidenceLayer('category', 'Semantic Objects',
evidence.semantic_objects?.map(obj => `${obj.label} (${(obj.confidence * 100).toFixed(0)}%)`), '#5856D6')}
{renderEvidenceLayer('text-fields', 'Text Detections',
evidence.text_detections?.map(t => t.text), '#FF9500')}
{renderEvidenceLayer('straighten', 'Geometric Features',
evidence.geometric_features ? [
`Horizon: ${evidence.geometric_features.horizon_detected ? 'Yes' : 'No'}`,
`Vanishing points: ${evidence.geometric_features.vanishing_points || 0}`,
] : [], '#AF52DE')}
{renderEvidenceLayer('wb-sunny', 'Environmental',
evidence.environmental_signals ? [
`Time: ${evidence.environmental_signals.time_of_day}`,
`Lighting: ${evidence.environmental_signals.lighting_quality}`,
`Weather: ${evidence.environmental_signals.weather || 'Unknown'}`,
] : [], '#FF3B30')}
{renderEvidenceLayer('history', 'Temporal',
evidence.temporal_signals ? [
`Season: ${evidence.temporal_signals.season}`,
`Day: ${evidence.temporal_signals.day_of_week}`,
] : [], '#5AC8FA')}
</ScrollView>
</Animated.View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000',
},
scrollView: {
flex: 1,
padding: 16,
},
confidenceHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
confidenceTitle: {
fontSize: 20,
fontWeight: '700',
color: '#fff',
},
confidenceBadge: {
backgroundColor: 'rgba(0,122,255,0.3)',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 16,
},
confidenceText: {
color: '#007AFF',
fontSize: 14,
fontWeight: '600',
},
layerCard: {
backgroundColor: '#1C1C1E',
borderRadius: 12,
padding: 16,
marginBottom: 12,
borderLeftWidth: 4,
},
layerHeader: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 8,
},
layerTitle: {
fontSize: 16,
fontWeight: '600',
marginLeft: 8,
flex: 1,
},
layerCount: {
fontSize: 14,
color: '#8E8E93',
fontWeight: '600',
},
layerItem: {
fontSize: 14,
color: '#8E8E93',
marginLeft: 28,
marginBottom: 4,
},
});