Pathora_Colposcopy_Assistant / src /pages /PatientRegistry.tsx
nusaibah0110's picture
Update application with new features and components
1c68fe6
import { useState } from 'react';
import { Eye, Edit2, ArrowLeft } from 'lucide-react';
import { sessionStore } from '../store/sessionStore';
import { generatePatientId, getPatientHistory, savePatientRecord } from '../store/patientIdStore';
type Props = {
onNewPatient: (newPatientId: string) => void;
onSelectExisting: (id: string) => void;
onBackToHome: () => void;
onNext: () => void;
};
export function PatientRegistry({ onNewPatient, onSelectExisting, onBackToHome, onNext }: Props) {
const [patientId, setPatientId] = useState('');
const [error, setError] = useState<string | null>(null);
const [results, setResults] = useState<Array<{ id: string; name: string; examDate: string }>>([]);
const [searched, setSearched] = useState(false);
// Demo in-memory patients; replace with real API later
const mockPatients = [
{ id: 'PT-2025-8492', name: 'Aisha Khan', examDate: '2025-01-10' },
{ id: 'P-10234', name: 'Sarah Johnson', examDate: '2024-01-15' },
{ id: 'P-10235', name: 'Emily Chen', examDate: '2024-01-15' }
];
// Get all available patients (demo + generated)
const allPatients = [...mockPatients, ...getPatientHistory()];
const handleSearch = () => {
const q = patientId.trim();
setSearched(true);
if (!q) {
setError('Please enter a Patient ID');
setResults([]);
return;
}
setError(null);
const found = allPatients.filter(p => p.id.toLowerCase() === q.toLowerCase());
setResults(found);
};
const handleAddNewPatient = () => {
const newId = generatePatientId();
onNewPatient(newId);
};
const handleSelectPatient = (patientRecord: { id: string; name: string; examDate: string }) => {
// Save patient info to sessionStore
sessionStore.merge({
patientInfo: {
id: patientRecord.id,
name: patientRecord.name,
examDate: patientRecord.examDate
}
});
// Call the parent handler
onSelectExisting(patientRecord.id);
};
return (
<div className="flex-1 flex flex-col items-stretch justify-start py-4 md:py-6 lg:py-8">
<div className="w-full px-4 py-2">
<button onClick={onBackToHome} className="flex items-center gap-2 px-4 py-2 hover:bg-gray-100 rounded-lg transition-colors text-gray-600">
<ArrowLeft className="w-5 h-5 md:w-6 md:h-6" />
<span className="text-sm md:text-base">Go to Homepage</span>
</button>
</div>
<div className="w-full max-w-6xl mx-auto mb-4 md:mb-6 px-4">
<h1 className="text-2xl md:text-3xl lg:text-4xl font-extrabold text-[#0A2540]">Patient Records</h1>
</div>
<div className="w-full mx-auto p-4 md:p-8 lg:p-12 bg-white h-full min-h-[60vh]">
<div className="mb-6 md:mb-8">
<p className="text-sm md:text-base lg:text-lg text-gray-600 mb-4">Search by Patient ID or add a new patient.</p>
<div className="space-y-4">
<label className="block text-sm md:text-base font-medium text-gray-600">Search by Patient ID</label>
<div className="flex flex-col lg:flex-row gap-3 md:gap-4 items-stretch lg:items-center">
<select onChange={e => {
const v = e.target.value;
if (v === 'all') {
setResults(allPatients);
setSearched(true);
} else if (v === 'clear') {
setResults([]);
setSearched(true);
}
}} className="px-4 py-3 md:py-4 border border-gray-200 rounded-lg bg-white text-sm md:text-base">
<option value="">Demo data</option>
<option value="all">Show all demo patients</option>
<option value="clear">Clear results</option>
</select>
<div className="flex flex-col md:flex-row gap-3 md:gap-4 w-full lg:w-auto lg:max-w-2xl">
<input aria-label="Search by Patient ID" value={patientId} onChange={e => setPatientId(e.target.value)} placeholder="e.g. PT-2025-8492" className="px-3 py-2 md:py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-[#05998c] outline-none text-sm md:text-base flex-1 lg:flex-none lg:w-48" />
<button onClick={handleSearch} className="px-4 md:px-6 py-2 md:py-3 bg-[#0A2540] text-white rounded-lg text-sm md:text-base font-medium hover:bg-[#051B30] transition-colors whitespace-nowrap">Search</button>
<button onClick={handleAddNewPatient} className="px-4 md:px-6 py-2 md:py-3 bg-[#05998c] text-white font-semibold rounded-lg text-sm md:text-base hover:bg-[#047569] transition-colors whitespace-nowrap">Add New Patient</button>
</div>
</div>
{error && <p className="text-sm md:text-base text-red-500 mt-2">{error}</p>}
</div>
</div>
<div>
{!searched && <p className="text-sm md:text-base text-gray-600">Enter a Patient ID and click Search.</p>}
{searched && results.length === 0 && <div className="py-8 text-center text-gray-600 text-sm md:text-base">No patient record found.</div>}
{results.length > 0 && (
<div className="mt-4 overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200 text-xs md:text-sm">
<thead className="bg-gray-50">
<tr>
<th className="px-3 md:px-4 py-2 md:py-3 text-left text-xs font-medium text-gray-500 uppercase">Patient ID</th>
<th className="px-3 md:px-4 py-2 md:py-3 text-left text-xs font-medium text-gray-500 uppercase">Patient Name</th>
<th className="px-3 md:px-4 py-2 md:py-3 text-left text-xs font-medium text-gray-500 uppercase">Examination Date</th>
<th className="px-3 md:px-4 py-2 md:py-3 text-left text-xs font-medium text-gray-500 uppercase">Actions</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-100">
{results.map(r => (
<tr key={r.id}>
<td className="px-3 md:px-4 py-2 md:py-3 text-[#0A2540] font-mono text-xs md:text-sm">{r.id}</td>
<td className="px-3 md:px-4 py-2 md:py-3 text-gray-700 font-medium text-xs md:text-sm">{r.name}</td>
<td className="px-3 md:px-4 py-2 md:py-3 text-gray-600 text-xs md:text-sm">{r.examDate}</td>
<td className="px-3 md:px-4 py-2 md:py-3 text-gray-600">
<div className="flex items-center gap-2 md:gap-3">
<button aria-label={`View ${r.id}`} title="View" onClick={() => handleSelectPatient(r)} className="p-1.5 md:p-2 rounded hover:bg-gray-50">
<Eye className="w-4 h-4 md:w-5 md:h-5 text-gray-600" />
</button>
<button aria-label={`Edit ${r.id}`} title="Edit" onClick={() => handleSelectPatient(r)} className="p-1.5 md:p-2 rounded hover:bg-gray-50">
<Edit2 className="w-4 h-4 md:w-5 md:h-5 text-gray-600" />
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
</div>
</div>
);
}
export default PatientRegistry;