/* * File: AIPredictionCard.tsx * Description: Card component for displaying AI prediction case information * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */ import React from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Dimensions, } from 'react-native'; import Icon from 'react-native-vector-icons/Feather'; import { theme } from '../../../theme'; import { AIPredictionCase, URGENCY_COLORS, SEVERITY_COLORS, CATEGORY_COLORS } from '../types'; // ============================================================================ // INTERFACES // ============================================================================ interface AIPredictionCardProps { predictionCase: AIPredictionCase; onPress: (predictionCase: AIPredictionCase) => void; onReview?: (caseId: string) => void; isSelected?: boolean; onToggleSelect?: (caseId: string) => void; showReviewButton?: boolean; } // ============================================================================ // CONSTANTS // ============================================================================ const { width } = Dimensions.get('window'); const CARD_WIDTH = width - 32; // Full width with margins // ============================================================================ // AI PREDICTION CARD COMPONENT // ============================================================================ /** * AIPredictionCard Component * * Purpose: Display AI prediction case information in a card format * * Features: * - Patient ID and hospital information * - AI prediction results with confidence score * - Urgency and severity indicators * - Review status and actions * - Selection support for bulk operations * - Modern card design with proper spacing * - Color-coded priority indicators * - Accessibility support */ const AIPredictionCard: React.FC = ({ predictionCase, onPress, onReview, isSelected = false, onToggleSelect, showReviewButton = true, }) => { // ============================================================================ // HELPER FUNCTIONS // ============================================================================ /** * Get Urgency Color * * Purpose: Get color based on clinical urgency */ const getUrgencyColor = (urgency: string): string => { return URGENCY_COLORS[urgency as keyof typeof URGENCY_COLORS] || theme.colors.textMuted; }; /** * Get Severity Color * * Purpose: Get color based on primary severity */ const getSeverityColor = (severity: string): string => { return SEVERITY_COLORS[severity as keyof typeof SEVERITY_COLORS] || theme.colors.textMuted; }; /** * Get Category Color * * Purpose: Get color based on finding category */ const getCategoryColor = (category: string): string => { return CATEGORY_COLORS[category as keyof typeof CATEGORY_COLORS] || theme.colors.textMuted; }; /** * Get Review Status Color * * Purpose: Get color based on review status */ const getReviewStatusColor = (status: string): string => { switch (status) { case 'confirmed': return theme.colors.success; case 'reviewed': return theme.colors.info; case 'disputed': return theme.colors.warning; case 'pending': default: return theme.colors.error; } }; /** * Format Confidence Score * * Purpose: Format confidence score as percentage */ const formatConfidence = (score: number): string => { return `${Math.round(score * 100)}%`; }; /** * Capitalize Text * * Purpose: Capitalize first letter of each word */ const capitalize = (text: string): string => { return text.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1) ).join(' '); }; /** * Format Date * * Purpose: Format date for display */ const formatDate = (dateString?: string): string => { if (!dateString) return 'N/A'; try { const date = new Date(dateString); return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', }); } catch { return 'N/A'; } }; // ============================================================================ // EVENT HANDLERS // ============================================================================ /** * Handle Card Press * * Purpose: Handle card tap to view details */ const handleCardPress = () => { onPress(predictionCase); }; /** * Handle Review Press * * Purpose: Handle review button press */ const handleReviewPress = (event: any) => { event.stopPropagation(); if (onReview) { onReview(predictionCase.patid); } }; /** * Handle Selection Toggle * * Purpose: Handle case selection toggle */ const handleSelectionToggle = (event: any) => { event.stopPropagation(); if (onToggleSelect) { onToggleSelect(predictionCase.patid); } }; // ============================================================================ // RENDER // ============================================================================ return ( {/* Header Section */} {predictionCase.patid} {formatDate(predictionCase.processed_at)} {onToggleSelect && ( )} {capitalize(predictionCase.prediction.clinical_urgency)} {/* Prediction Information */} {capitalize(predictionCase.prediction.label)} {formatConfidence(predictionCase.prediction.confidence_score)} {/* Finding Details */} Type: {capitalize(predictionCase.prediction.finding_type)} Category: {capitalize(predictionCase.prediction.finding_category)} {/* Severity and Location */} {capitalize(predictionCase.prediction.primary_severity)} Severity {predictionCase.prediction.anatomical_location !== 'not_applicable' && ( {capitalize(predictionCase.prediction.anatomical_location)} )} {/* Footer Section */} {capitalize(predictionCase.review_status || 'pending')} {predictionCase.reviewed_by && ( by {predictionCase.reviewed_by} )} {showReviewButton && predictionCase.review_status === 'pending' && ( Review )} ); }; // ============================================================================ // STYLES // ============================================================================ const styles = StyleSheet.create({ container: { backgroundColor: theme.colors.background, borderRadius: theme.borderRadius.large, padding: theme.spacing.lg, marginHorizontal: theme.spacing.md, marginVertical: theme.spacing.sm, width: CARD_WIDTH, ...theme.shadows.medium, borderWidth: 1, borderColor: theme.colors.border, }, selectedContainer: { borderColor: theme.colors.primary, borderWidth: 2, }, emergencyContainer: { borderLeftWidth: 4, borderLeftColor: URGENCY_COLORS.emergency, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: theme.spacing.md, }, headerLeft: { flex: 1, }, headerRight: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing.sm, }, patientId: { fontSize: theme.typography.fontSize.bodyLarge, fontWeight: theme.typography.fontWeight.bold, color: theme.colors.textPrimary, marginBottom: theme.spacing.xs, }, date: { fontSize: theme.typography.fontSize.bodySmall, color: theme.colors.textSecondary, }, selectionButton: { padding: theme.spacing.xs, }, priorityBadge: { paddingHorizontal: theme.spacing.sm, paddingVertical: theme.spacing.xs, borderRadius: theme.borderRadius.small, }, priorityText: { fontSize: theme.typography.fontSize.caption, fontWeight: theme.typography.fontWeight.medium, color: theme.colors.background, }, predictionSection: { marginBottom: theme.spacing.md, }, predictionHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: theme.spacing.sm, }, predictionLabel: { fontSize: theme.typography.fontSize.bodyLarge, fontWeight: theme.typography.fontWeight.medium, color: theme.colors.textPrimary, flex: 1, marginRight: theme.spacing.sm, }, confidenceContainer: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing.xs, }, confidenceText: { fontSize: theme.typography.fontSize.bodyMedium, fontWeight: theme.typography.fontWeight.medium, color: theme.colors.primary, }, findingDetails: { marginBottom: theme.spacing.sm, }, findingItem: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: theme.spacing.xs, }, findingLabel: { fontSize: theme.typography.fontSize.bodyMedium, color: theme.colors.textSecondary, fontWeight: theme.typography.fontWeight.medium, }, findingValue: { fontSize: theme.typography.fontSize.bodyMedium, color: theme.colors.textPrimary, }, categoryBadge: { paddingHorizontal: theme.spacing.sm, paddingVertical: theme.spacing.xs, borderRadius: theme.borderRadius.small, }, categoryText: { fontSize: theme.typography.fontSize.caption, fontWeight: theme.typography.fontWeight.medium, color: theme.colors.background, }, detailsRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, detailItem: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing.xs, flex: 1, }, detailText: { fontSize: theme.typography.fontSize.bodySmall, color: theme.colors.textSecondary, }, footer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingTop: theme.spacing.sm, borderTopWidth: 1, borderTopColor: theme.colors.border, }, footerLeft: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing.sm, flex: 1, }, reviewStatusBadge: { paddingHorizontal: theme.spacing.sm, paddingVertical: theme.spacing.xs, borderRadius: theme.borderRadius.small, }, reviewStatusText: { fontSize: theme.typography.fontSize.caption, fontWeight: theme.typography.fontWeight.medium, color: theme.colors.background, }, reviewedBy: { fontSize: theme.typography.fontSize.caption, color: theme.colors.textMuted, fontStyle: 'italic', }, reviewButton: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing.xs, paddingHorizontal: theme.spacing.sm, paddingVertical: theme.spacing.xs, borderRadius: theme.borderRadius.small, borderWidth: 1, borderColor: theme.colors.primary, }, reviewButtonText: { fontSize: theme.typography.fontSize.bodySmall, color: theme.colors.primary, fontWeight: theme.typography.fontWeight.medium, }, }); export default AIPredictionCard; /* * End of File: AIPredictionCard.tsx * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */