NeoScan_Radiologist/app/modules/Dashboard/components/PatientCard.tsx
2025-08-05 18:01:36 +05:30

362 lines
12 KiB
TypeScript

/*
* File: PatientCard.tsx
* Description: Patient card component displaying patient information and status
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/
import React from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
} from 'react-native';
import { theme } from '../../../theme/theme';
import { Patient } from '../../../shared/types/patient';
import { getPriorityColor, getStatusColor, calculateAge } from '../../../shared/utils/helpers';
/**
* PatientCardProps Interface
*
* Purpose: Defines the props required by the PatientCard component
*
* Props:
* - patient: Patient data object containing all patient information
* - onPress: Callback function triggered when the card is pressed
*/
interface PatientCardProps {
patient: Patient;
onPress: (patient: Patient) => void;
}
/**
* PatientCard Component
*
* Purpose: Display comprehensive patient information in a compact, touchable card format
*
* Features:
* 1. Patient identification (name, age, gender, MRN)
* 2. Priority and status badges with color coding
* 3. Location information (bed, room, attending physician)
* 4. Real-time vital signs display
* 5. Allergy warnings (if any)
* 6. Current diagnosis and last update time
*
* Data Display:
* - Header: Patient name, demographics, and status badges
* - Location: Bed/room assignment and attending physician
* - Vital Signs: BP, HR, Temperature, Oxygen saturation
* - Allergies: Warning display for known allergies
* - Footer: Current diagnosis and timestamp
*
* Interaction:
* - Touchable card that navigates to detailed patient view
* - Visual feedback with activeOpacity for better UX
*/
export const PatientCard: React.FC<PatientCardProps> = ({
patient,
onPress,
}) => {
// ============================================================================
// DATA PROCESSING
// ============================================================================
// Calculate patient age from date of birth
const age = calculateAge(patient.dateOfBirth);
// Get color coding for priority and status badges
const priorityColor = getPriorityColor(patient.priority); // Color based on priority level
const statusColor = getStatusColor(patient.status); // Color based on patient status
/**
* formatVitalSigns Function
*
* Purpose: Format vital signs data for display in the card
*
* Returns:
* - bp: Blood pressure in systolic/diastolic format
* - hr: Heart rate value
* - temp: Temperature in Celsius
* - o2: Oxygen saturation percentage
*/
const formatVitalSigns = () => {
const { vitalSigns } = patient;
return {
bp: `${vitalSigns.bloodPressure.systolic}/${vitalSigns.bloodPressure.diastolic}`, // Format: 120/80
hr: vitalSigns.heartRate.value, // Heart rate: 75
temp: vitalSigns.temperature.value, // Temperature: 37.2
o2: vitalSigns.oxygenSaturation.value, // Oxygen: 98
};
};
// Format vital signs for display
const vitals = formatVitalSigns();
// ============================================================================
// RENDER SECTION
// ============================================================================
return (
<TouchableOpacity
style={styles.container}
onPress={() => onPress(patient)} // Navigate to patient details
activeOpacity={0.7} // Visual feedback on touch
>
{/* ========================================================================
* HEADER SECTION - Patient identification and status badges
* ======================================================================== */}
<View style={styles.header}>
{/* Patient information section */}
<View style={styles.patientInfo}>
{/* Patient full name */}
<Text style={styles.patientName}>
{patient.firstName} {patient.lastName}
</Text>
{/* Patient demographics and MRN */}
<Text style={styles.patientDetails}>
{age} years {patient.gender} MRN: {patient.mrn}
</Text>
</View>
{/* Status badges section */}
<View style={styles.badges}>
{/* Priority badge with color coding */}
<View style={[styles.badge, { backgroundColor: priorityColor + '20' }]}>
<Text style={[styles.badgeText, { color: priorityColor }]}>
{patient.priority}
</Text>
</View>
{/* Status badge with color coding */}
<View style={[styles.badge, { backgroundColor: statusColor + '20' }]}>
<Text style={[styles.badgeText, { color: statusColor }]}>
{patient.status}
</Text>
</View>
</View>
</View>
{/* ========================================================================
* LOCATION SECTION - Bed assignment and attending physician
* ======================================================================== */}
<View style={styles.locationInfo}>
{/* Bed and room location */}
<Text style={styles.locationText}>
Bed {patient.bedNumber} Room {patient.roomNumber}
</Text>
{/* Attending physician */}
<Text style={styles.attendingText}>
Dr. {patient.attendingPhysician}
</Text>
</View>
{/* ========================================================================
* VITAL SIGNS SECTION - Real-time patient vitals
* ======================================================================== */}
<View style={styles.vitalSigns}>
{/* Blood Pressure */}
<View style={styles.vitalItem}>
<Text style={styles.vitalLabel}>BP</Text>
<Text style={styles.vitalValue}>{vitals.bp}</Text>
</View>
{/* Heart Rate */}
<View style={styles.vitalItem}>
<Text style={styles.vitalLabel}>HR</Text>
<Text style={styles.vitalValue}>{vitals.hr}</Text>
</View>
{/* Temperature */}
<View style={styles.vitalItem}>
<Text style={styles.vitalLabel}>Temp</Text>
<Text style={styles.vitalValue}>{vitals.temp}°C</Text>
</View>
{/* Oxygen Saturation */}
<View style={styles.vitalItem}>
<Text style={styles.vitalLabel}>O</Text>
<Text style={styles.vitalValue}>{vitals.o2}%</Text>
</View>
</View>
{/* ========================================================================
* ALLERGIES SECTION - Warning display for known allergies
* ======================================================================== */}
{patient.allergies.length > 0 && (
<View style={styles.allergiesContainer}>
<Text style={styles.allergiesLabel}>Allergies:</Text>
<Text style={styles.allergiesText}>
{patient.allergies.map(a => a.name).join(', ')}
</Text>
</View>
)}
{/* ========================================================================
* FOOTER SECTION - Diagnosis and last update time
* ======================================================================== */}
<View style={styles.footer}>
{/* Current diagnosis */}
<Text style={styles.diagnosisText}>
{patient.currentDiagnosis}
</Text>
{/* Last update timestamp */}
<Text style={styles.timeText}>
Updated {new Date(patient.lastUpdated).toLocaleTimeString()}
</Text>
</View>
</TouchableOpacity>
);
};
// ============================================================================
// STYLES SECTION
// ============================================================================
const styles = StyleSheet.create({
// Main card container with shadow and rounded corners
container: {
backgroundColor: theme.colors.cardBackground,
borderRadius: theme.borderRadius.large,
padding: theme.spacing.md,
marginHorizontal: theme.spacing.md,
marginVertical: theme.spacing.sm,
...theme.shadows.small, // Add subtle shadow for elevation
},
// Header section with patient info and badges
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
marginBottom: theme.spacing.sm,
},
// Patient information container
patientInfo: {
flex: 1, // Take available space
},
// Patient name styling
patientName: {
fontSize: theme.typography.fontSize.bodyLarge,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
marginBottom: theme.spacing.xs,
},
// Patient details styling (age, gender, MRN)
patientDetails: {
fontSize: theme.typography.fontSize.bodySmall,
color: theme.colors.textSecondary,
},
// Badges container for priority and status
badges: {
flexDirection: 'row',
gap: theme.spacing.xs, // Space between badges
},
// Individual badge styling
badge: {
paddingHorizontal: theme.spacing.sm,
paddingVertical: theme.spacing.xs,
borderRadius: theme.borderRadius.small,
},
// Badge text styling
badgeText: {
fontSize: theme.typography.fontSize.caption,
fontFamily: theme.typography.fontFamily.medium,
},
// Location information container
locationInfo: {
marginBottom: theme.spacing.sm,
},
// Bed and room location text
locationText: {
fontSize: theme.typography.fontSize.bodyMedium,
color: theme.colors.textPrimary,
fontFamily: theme.typography.fontFamily.medium,
},
// Attending physician text
attendingText: {
fontSize: theme.typography.fontSize.bodySmall,
color: theme.colors.textSecondary,
},
// Vital signs container with background
vitalSigns: {
flexDirection: 'row',
justifyContent: 'space-between',
backgroundColor: theme.colors.backgroundAccent, // Light background for vitals
borderRadius: theme.borderRadius.medium,
padding: theme.spacing.sm,
marginBottom: theme.spacing.sm,
},
// Individual vital sign item
vitalItem: {
alignItems: 'center', // Center align label and value
},
// Vital sign label (BP, HR, Temp, O₂)
vitalLabel: {
fontSize: theme.typography.fontSize.caption,
color: theme.colors.textSecondary,
fontFamily: theme.typography.fontFamily.medium,
marginBottom: theme.spacing.xs,
},
// Vital sign value styling
vitalValue: {
fontSize: theme.typography.fontSize.bodyMedium,
color: theme.colors.textPrimary,
fontFamily: theme.typography.fontFamily.bold,
},
// Allergies container
allergiesContainer: {
marginBottom: theme.spacing.sm,
},
// Allergies label with warning color
allergiesLabel: {
fontSize: theme.typography.fontSize.bodySmall,
color: theme.colors.warning, // Warning color for allergies
fontFamily: theme.typography.fontFamily.medium,
marginBottom: theme.spacing.xs,
},
// Allergies text listing
allergiesText: {
fontSize: theme.typography.fontSize.bodySmall,
color: theme.colors.textSecondary,
},
// Footer container with diagnosis and timestamp
footer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
// Current diagnosis text
diagnosisText: {
fontSize: theme.typography.fontSize.bodyMedium,
color: theme.colors.textPrimary,
fontFamily: theme.typography.fontFamily.medium,
flex: 1, // Take available space
},
// Last update timestamp
timeText: {
fontSize: theme.typography.fontSize.caption,
color: theme.colors.textMuted,
},
});
/*
* End of File: PatientCard.tsx
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/