| 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); |
|
|
| |
| 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' } |
| ]; |
|
|
| |
| 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 }) => { |
| |
| sessionStore.merge({ |
| patientInfo: { |
| id: patientRecord.id, |
| name: patientRecord.name, |
| examDate: patientRecord.examDate |
| } |
| }); |
| |
| 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; |
|
|