/* * File: FeedbackDetailScreen.tsx * Description: Feedback detail screen for a specific series showing feedback history (read-only) * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. * * Features: * - Display feedback history for the series (read-only) * - Feedback data received from navigation parameters * - Clinical insights and feedback analytics * - Modern healthcare-focused UI design */ import React, { useEffect, useState, useCallback } from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert, TextInput, RefreshControl, } from 'react-native'; import { theme } from '../../../theme/theme'; import { useAppDispatch, useAppSelector } from '../../../store/hooks'; import Icon from 'react-native-vector-icons/Feather'; import { SafeAreaView } from 'react-native-safe-area-context'; // Import types and API import { selectUser } from '../../Auth/redux/authSelectors'; import { FeedbackDetailScreenProps } from '../../Dashboard/navigation/navigationTypes'; // ============================================================================ // INTERFACES // ============================================================================ interface SeriesSummary { series_num: string; series_description: string; total_images: number; png_preview: string; modality: string; } interface Feedback { feedback_id: string; user_id: string; feedback_text: string; is_positive: boolean; email: string; created_at: string; prediction_id: number; prediction_file_path: string; series_number: string; feedback_type: string; } interface PatientData { patid: string; hospital_id: string; patient_info: { name: string; age: string; sex: string; date: string; institution: string; modality: string; status: string; report_status: string; file_name: string; file_type: string; frame_count: number; }; series_summary: SeriesSummary[]; processing_metadata: any; total_predictions: number; first_processed_at: string; last_processed_at: string; } // ============================================================================ // FEEDBACK DETAIL SCREEN COMPONENT // ============================================================================ /** * FeedbackDetailScreen Component * * Purpose: Display feedback details and history for a specific series (read-only) * * Features: * - Feedback history display (read-only) * - Clinical insights and analytics * - Modern healthcare-focused UI design */ const FeedbackDetailScreen: React.FC = ({ navigation, route }) => { // ============================================================================ // STATE MANAGEMENT // ============================================================================ const dispatch = useAppDispatch(); // Route parameters const { patientId, patientName, seriesNumber, seriesData, patientData, feedbackData, onFeedbackSubmitted } = route.params; // Redux state const user = useAppSelector(selectUser); // Local state const [isLoading, setIsLoading] = useState(false); const [isRefreshing, setIsRefreshing] = useState(false); const [error, setError] = useState(null); // ============================================================================ // EFFECTS // ============================================================================ /** * Component Mount Effect * * Purpose: Initialize screen and set navigation title */ useEffect(() => { navigation.setOptions({ title: `Feedback - Series ${seriesNumber}`, headerShown: true, headerLeft: () => ( ), }); }, [navigation, seriesNumber, patientId]); // ============================================================================ // EVENT HANDLERS // ============================================================================ /** * Handle Back Navigation * * Purpose: Navigate back to previous screen */ const handleBackPress = useCallback(() => { navigation.goBack(); }, [navigation]); /** * Handle Refresh * * Purpose: Pull-to-refresh functionality */ const handleRefresh = useCallback(async () => { setIsRefreshing(true); // TODO: Implement actual refresh logic setTimeout(() => { setIsRefreshing(false); }, 1000); }, []); /** * Handle Back to Patient Details * * Purpose: Navigate to PatientDetails screen within the Dashboard stack * * Note: Now that both screens are in the same Dashboard stack, * navigation should work smoothly without loops. */ const handleBackToPatientDetails = useCallback(() => { try { // Navigate to PatientDetails screen in the same stack navigation.navigate('PatientDetails', { patientId: patientId, patient: patientData || { name: patientName || 'Unknown Patient' }, }); } catch (error) { console.warn('Navigation to PatientDetails failed:', error); // Fallback: go back to previous screen navigation.goBack(); } }, [navigation, patientId, patientName, patientData]); // ============================================================================ // UTILITY FUNCTIONS // ============================================================================ /** * Get Feedback Type Color * * Purpose: Get appropriate color for feedback type * * @param feedbackType - Type of feedback */ const getFeedbackTypeColor = (feedbackType: string) => { switch (feedbackType.toLowerCase()) { case 'clinical_accuracy': return theme.colors.success; case 'confidence_assessment': return theme.colors.warning; case 'technical_issue': return theme.colors.error; default: return theme.colors.info; } }; /** * Get Series Feedback * * Purpose: Get feedback for the current series */ const getSeriesFeedback = () => { return feedbackData?.filter((feedback: Feedback) => feedback.series_number === seriesNumber) || []; }; /** * Is Feedback New * * Purpose: Check if feedback is recent (within 24 hours) * * @param feedbackId - Feedback ID to check */ const isFeedbackNew = (feedbackId: string) => { const feedback = feedbackData?.find((f: Feedback) => f.feedback_id === feedbackId); if (!feedback) return false; const feedbackDate = new Date(feedback.created_at); const now = new Date(); const diffHours = (now.getTime() - feedbackDate.getTime()) / (1000 * 60 * 60); return diffHours < 24; }; // ============================================================================ // RENDER HELPERS // ============================================================================ /** * Render Series Header * * Purpose: Render series information header */ const renderSeriesHeader = () => { if (!seriesData) return null; return ( Series {seriesData.series_description} {seriesData.total_images} images • {seriesData.modality} modality Processed {patientData && ( {patientData.patient_info.name} • ID: {patientData.patid} View Details )} ); }; /** * Render Feedback History * * Purpose: Render feedback history display only */ const renderFeedbackHistory = () => { const seriesFeedbacks = getSeriesFeedback(); return ( {/* Feedback History */} Feedback History ({seriesFeedbacks.length}) {seriesFeedbacks.length === 0 ? ( No Feedback Yet No feedback has been provided for this series yet ) : ( seriesFeedbacks.map((feedback: Feedback) => ( {feedback.email} {isFeedbackNew(feedback.feedback_id) && ( NEW )} {new Date(feedback.created_at).toLocaleDateString()} {feedback.feedback_text} {feedback.feedback_type.replace('_', ' ').toUpperCase()} )) )} ); }; // ============================================================================ // MAIN RENDER // ============================================================================ return ( {/* Fixed Series Header */} {renderSeriesHeader()} {/* Scrollable Feedback Content */} } > {/* Feedback History from Navigation Parameters */} {renderFeedbackHistory()} ); }; // ============================================================================ // STYLES // ============================================================================ const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: theme.colors.background, }, // Series Header Styles seriesHeader: { backgroundColor: theme.colors.background, padding: theme.spacing.md, borderBottomWidth: 1, borderBottomColor: theme.colors.border, }, // Fixed Feedback Title Styles fixedFeedbackTitle: { backgroundColor: theme.colors.background, padding: theme.spacing.md, borderBottomWidth: 1, borderBottomColor: theme.colors.border, }, seriesHeaderTop: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: theme.spacing.sm, }, seriesHeaderLeft: { flex: 1, marginRight: theme.spacing.md, }, seriesHeaderRight: { alignItems: 'flex-end', }, seriesTitle: { fontSize: 18, color: theme.colors.textPrimary, fontFamily: theme.typography.fontFamily.bold, marginBottom: 4, }, seriesMeta: { fontSize: 14, color: theme.colors.textSecondary, fontFamily: theme.typography.fontFamily.regular, }, seriesStatusBadge: { flexDirection: 'row', alignItems: 'center', backgroundColor: theme.colors.success, paddingHorizontal: 8, paddingVertical: 4, borderRadius: 12, }, seriesStatusText: { fontSize: 10, color: theme.colors.background, fontFamily: theme.typography.fontFamily.bold, marginLeft: 4, textTransform: 'uppercase', }, patientInfoRow: { flexDirection: 'row', alignItems: 'center', }, patientInfoText: { fontSize: 14, color: theme.colors.textSecondary, fontFamily: theme.typography.fontFamily.regular, marginLeft: theme.spacing.xs, flex: 1, }, patientDetailButton: { padding: theme.spacing.xs, marginLeft: theme.spacing.sm, backgroundColor: theme.colors.tertiary, borderRadius: 16, borderWidth: 1, borderColor: theme.colors.primary, }, patientDetailButtonContent: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 8, paddingVertical: 4, }, patientDetailButtonText: { fontSize: 11, color: theme.colors.primary, fontFamily: theme.typography.fontFamily.medium, marginLeft: 4, textTransform: 'uppercase', }, // Content Styles scrollableContent: { flex: 1, }, content: { flex: 1, }, // Section Styles sectionTitle: { fontSize: 18, color: theme.colors.textPrimary, fontFamily: theme.typography.fontFamily.bold, marginBottom: theme.spacing.md, }, // Feedback Styles feedbackHistory: { padding: theme.spacing.md, }, // Feedback List Styles feedbackList: { marginTop: theme.spacing.sm, }, feedbackListTitle: { fontSize: 16, color: theme.colors.textPrimary, fontFamily: theme.typography.fontFamily.bold, marginBottom: theme.spacing.md, }, feedbackCard: { backgroundColor: theme.colors.backgroundAlt, borderRadius: 8, padding: theme.spacing.md, marginBottom: theme.spacing.sm, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 2, }, feedbackCardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: theme.spacing.sm, }, feedbackCardHeaderLeft: { flexDirection: 'row', alignItems: 'center', flex: 1, }, feedbackTypeIndicator: { width: 20, height: 20, borderRadius: 10, justifyContent: 'center', alignItems: 'center', marginRight: theme.spacing.sm, }, feedbackEmail: { fontSize: 12, color: theme.colors.textSecondary, fontFamily: theme.typography.fontFamily.medium, marginRight: theme.spacing.sm, }, newFeedbackBadge: { backgroundColor: theme.colors.error, paddingHorizontal: 6, paddingVertical: 2, borderRadius: 8, }, newFeedbackBadgeText: { fontSize: 8, color: theme.colors.background, fontFamily: theme.typography.fontFamily.bold, textTransform: 'uppercase', }, feedbackTimestamp: { fontSize: 10, color: theme.colors.textMuted, fontFamily: theme.typography.fontFamily.regular, }, feedbackText: { fontSize: 14, color: theme.colors.textPrimary, fontFamily: theme.typography.fontFamily.regular, lineHeight: 20, marginBottom: theme.spacing.sm, }, feedbackCardFooter: { alignItems: 'flex-end', }, feedbackTypeBadge: { paddingHorizontal: 8, paddingVertical: 4, borderRadius: 12, }, feedbackTypeBadgeText: { fontSize: 10, color: theme.colors.background, fontFamily: theme.typography.fontFamily.bold, textTransform: 'uppercase', }, // Empty State Styles emptyFeedbackState: { alignItems: 'center', justifyContent: 'center', paddingVertical: theme.spacing.xl, }, emptyFeedbackTitle: { fontSize: 18, color: theme.colors.textPrimary, fontFamily: theme.typography.fontFamily.bold, marginTop: theme.spacing.md, marginBottom: theme.spacing.sm, }, emptyFeedbackSubtitle: { fontSize: 14, color: theme.colors.textSecondary, fontFamily: theme.typography.fontFamily.regular, textAlign: 'center', lineHeight: 20, }, // Header Back Button Style headerBackButton: { padding: theme.spacing.sm, marginLeft: theme.spacing.xs, }, }); export default FeedbackDetailScreen; /* * End of File: FeedbackDetailScreen.tsx * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */