Changeset 48d2bed for frontend/src/pages/medical-records
Legend:
- Unmodified
- Added
- Removed
-
frontend/src/pages/medical-records/MedicalRecordDetail.js
rae6cd79 r48d2bed 57 57 const [prescriptions, setPrescriptions] = useState([]); 58 58 const [labTests, setLabTests] = useState([]); 59 const [labTechnicians, setLabTechnicians] = useState([]); 59 60 const [procedures, setProcedures] = useState([]); 60 61 … … 62 63 const [labTestForm, setLabTestForm] = useState({ 63 64 testId: '', 65 technicianId: '', 64 66 testDate: new Date().toISOString().split('T')[0], 65 67 notes: '', … … 141 143 console.log('Lab Tests:', testsRes.data); 142 144 145 const techniciansRes = await labService.getAllLabTechnicians(); 146 console.log('Lab Technicians:', techniciansRes.data); 147 143 148 const proceduresRes = await procedureService.getAllProcedures(); 144 149 console.log('Procedures:', proceduresRes.data); … … 149 154 setPrescriptions(prescriptionsRes.data || []); 150 155 setLabTests(testsRes.data || []); 156 setLabTechnicians(techniciansRes.data || []); 151 157 setProcedures(proceduresRes.data || []); 152 158 console.log('Dropdown options set successfully'); … … 273 279 if (!record) { 274 280 return ( 275 <div>276 <ErrorAlert message="Medical record not found" onClose={() => navigate('/medical-records')} />277 </div>281 <div> 282 <ErrorAlert message="Medical record not found" onClose={() => navigate('/medical-records')} /> 283 </div> 278 284 ); 279 285 } 280 286 281 287 return ( 282 <div> 283 <div className="flex justify-between items-center mb-6"> 284 <h1 style={{ fontSize: '36px', fontWeight: 'normal' }}>Medical Record</h1> 285 <button 286 onClick={() => navigate('/medical-records')} 287 className="bg-gray-300 text-gray-700 px-4 py-2 rounded hover:bg-gray-400" 288 > 289 Back 290 </button> 291 </div> 292 293 {error && <ErrorAlert message={error} onClose={() => setError(null)} />} 294 {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />} 295 296 {/* Patient Info */} 297 <div className="bg-white rounded-lg shadow p-6 mb-6"> 298 <h2 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Patient Information</h2> 299 <div className="grid grid-cols-4 gap-4"> 300 <div> 301 <p className="font-normal text-sm text-gray-600">Patient Name</p> 302 <p className="font-normal">{record.patientName}</p> 303 </div> 304 <div> 305 <p className="font-normal text-sm text-gray-600">EMBG</p> 306 <p className="font-normal">{record.embg}</p> 307 </div> 308 <div> 309 <p className="font-normal text-sm text-gray-600">Record ID</p> 310 <p className="font-normal">{record.recordId}</p> 311 </div> 312 <div> 313 <p className="font-normal text-sm text-gray-600">Patient ID</p> 314 <p className="font-normal">{record.patientId}</p> 288 <div> 289 <div className="flex justify-between items-center mb-6"> 290 <h1 style={{ fontSize: '36px', fontWeight: 'normal' }}>Medical Record</h1> 291 <button 292 onClick={() => navigate('/medical-records')} 293 className="bg-gray-300 text-gray-700 px-4 py-2 rounded hover:bg-gray-400" 294 > 295 Back 296 </button> 297 </div> 298 299 {error && <ErrorAlert message={error} onClose={() => setError(null)} />} 300 {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />} 301 302 {/* Patient Info */} 303 <div className="bg-white rounded-lg shadow p-6 mb-6"> 304 <h2 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Patient Information</h2> 305 <div className="grid grid-cols-4 gap-4"> 306 <div> 307 <p className="font-normal text-sm text-gray-600">Patient Name</p> 308 <p className="font-normal">{record.patientName}</p> 309 </div> 310 <div> 311 <p className="font-normal text-sm text-gray-600">EMBG</p> 312 <p className="font-normal">{record.embg}</p> 313 </div> 314 <div> 315 <p className="font-normal text-sm text-gray-600">Record ID</p> 316 <p className="font-normal">{record.recordId}</p> 317 </div> 318 <div> 319 <p className="font-normal text-sm text-gray-600">Patient ID</p> 320 <p className="font-normal">{record.patientId}</p> 321 </div> 315 322 </div> 316 323 </div> 317 </div> 318 319 {/* Tabs */} 320 <div className="flex gap-2 mb-6 border-b"> 321 <button 322 onClick={() => setActiveTab('view')} 323 style={{ fontWeight: 'normal' }} 324 className={`px-6 py-3 ${ 325 activeTab === 'view' 326 ? 'border-b-2 border-purple-600 text-purple-600' 327 : 'text-purple-600 hover:text-purple-700' 328 }`} 329 > 330 View Medical Data 331 </button> 332 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 333 <button 334 onClick={() => setActiveTab('diagnosis')} 335 style={{ fontWeight: 'normal' }} 336 className={`px-6 py-3 ${ 337 activeTab === 'diagnosis' 338 ? 'border-b-2 border-purple-600 text-purple-600' 339 : 'text-purple-600 hover:text-purple-700' 340 }`} 341 > 342 Record Diagnosis 343 </button> 344 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 345 <button 346 onClick={() => setActiveTab('symptoms')} 347 style={{ fontWeight: 'normal' }} 348 className={`px-6 py-3 ${ 349 activeTab === 'symptoms' 350 ? 'border-b-2 border-purple-600 text-purple-600' 351 : 'text-purple-600 hover:text-purple-700' 352 }`} 353 > 354 Record Symptoms 355 </button> 356 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 357 <button 358 onClick={() => setActiveTab('allergies')} 359 style={{ fontWeight: 'normal' }} 360 className={`px-6 py-3 ${ 361 activeTab === 'allergies' 362 ? 'border-b-2 border-purple-600 text-purple-600' 363 : 'text-purple-600 hover:text-purple-700' 364 }`} 365 > 366 Record Allergies 367 </button> 368 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 369 <button 370 onClick={() => setActiveTab('prescription')} 371 style={{ fontWeight: 'normal' }} 372 className={`px-6 py-3 ${ 373 activeTab === 'prescription' 374 ? 'border-b-2 border-purple-600 text-purple-600' 375 : 'text-purple-600 hover:text-purple-700' 376 }`} 377 > 378 Record Prescription 379 </button> 380 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 381 <button 382 onClick={() => setActiveTab('lab-tests')} 383 style={{ fontWeight: 'normal' }} 384 className={`px-6 py-3 ${ 385 activeTab === 'lab-tests' 386 ? 'border-b-2 border-purple-600 text-purple-600' 387 : 'text-purple-600 hover:text-purple-700' 388 }`} 389 > 390 Request Lab Test 391 </button> 392 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 393 <button 394 onClick={() => setActiveTab('procedures')} 395 style={{ fontWeight: 'normal' }} 396 className={`px-6 py-3 ${ 397 activeTab === 'procedures' 398 ? 'border-b-2 border-purple-600 text-purple-600' 399 : 'text-purple-600 hover:text-purple-700' 400 }`} 401 > 402 Request Procedure 403 </button> 404 </div> 405 406 {/* View Medical Data Tab */} 407 {activeTab === 'view' && ( 408 <div className="space-y-6"> 409 {/* Diagnoses */} 410 {record.diagnoses && record.diagnoses.length > 0 && ( 411 <div className="bg-white rounded-lg shadow p-6"> 412 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Diagnoses</h3> 413 <div className="space-y-3"> 414 {record.diagnoses.map((diagnosis) => ( 415 <div key={diagnosis.diagnosisId} className="border-l-4 border-purple-500 pl-4 py-2"> 416 <p className="font-normal" style={{ fontSize: '18px' }}>{diagnosis.name}</p> 417 {diagnosis.description && ( 418 <p className="font-normal text-gray-600 text-sm">{diagnosis.description}</p> 419 )} 420 <p className="font-normal text-xs text-gray-500">By: {diagnosis.doctorName}</p> 421 </div> 422 ))} 423 </div> 424 </div> 425 )} 426 427 {/* Symptoms */} 428 {record.symptoms && record.symptoms.length > 0 && ( 429 <div className="bg-white rounded-lg shadow p-6"> 430 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Symptoms</h3> 431 <div className="flex flex-wrap gap-2"> 432 {record.symptoms.map((symptom) => ( 433 <span 434 key={symptom.symptomId} 435 className="bg-yellow-100 text-yellow-800 px-3 py-1 rounded-full text-sm font-normal" 436 > 324 325 {/* Tabs */} 326 <div className="flex gap-2 mb-6 border-b"> 327 <button 328 onClick={() => setActiveTab('view')} 329 style={{ fontWeight: 'normal' }} 330 className={`px-6 py-3 ${ 331 activeTab === 'view' 332 ? 'border-b-2 border-purple-600 text-purple-600' 333 : 'text-purple-600 hover:text-purple-700' 334 }`} 335 > 336 View Medical Data 337 </button> 338 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 339 <button 340 onClick={() => setActiveTab('diagnosis')} 341 style={{ fontWeight: 'normal' }} 342 className={`px-6 py-3 ${ 343 activeTab === 'diagnosis' 344 ? 'border-b-2 border-purple-600 text-purple-600' 345 : 'text-purple-600 hover:text-purple-700' 346 }`} 347 > 348 Record Diagnosis 349 </button> 350 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 351 <button 352 onClick={() => setActiveTab('symptoms')} 353 style={{ fontWeight: 'normal' }} 354 className={`px-6 py-3 ${ 355 activeTab === 'symptoms' 356 ? 'border-b-2 border-purple-600 text-purple-600' 357 : 'text-purple-600 hover:text-purple-700' 358 }`} 359 > 360 Record Symptoms 361 </button> 362 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 363 <button 364 onClick={() => setActiveTab('allergies')} 365 style={{ fontWeight: 'normal' }} 366 className={`px-6 py-3 ${ 367 activeTab === 'allergies' 368 ? 'border-b-2 border-purple-600 text-purple-600' 369 : 'text-purple-600 hover:text-purple-700' 370 }`} 371 > 372 Record Allergies 373 </button> 374 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 375 <button 376 onClick={() => setActiveTab('prescription')} 377 style={{ fontWeight: 'normal' }} 378 className={`px-6 py-3 ${ 379 activeTab === 'prescription' 380 ? 'border-b-2 border-purple-600 text-purple-600' 381 : 'text-purple-600 hover:text-purple-700' 382 }`} 383 > 384 Record Prescription 385 </button> 386 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 387 <button 388 onClick={() => setActiveTab('lab-tests')} 389 style={{ fontWeight: 'normal' }} 390 className={`px-6 py-3 ${ 391 activeTab === 'lab-tests' 392 ? 'border-b-2 border-purple-600 text-purple-600' 393 : 'text-purple-600 hover:text-purple-700' 394 }`} 395 > 396 Request Lab Test 397 </button> 398 <span className="text-gray-600 px-3" style={{ fontWeight: 'normal' }}>|</span> 399 <button 400 onClick={() => setActiveTab('procedures')} 401 style={{ fontWeight: 'normal' }} 402 className={`px-6 py-3 ${ 403 activeTab === 'procedures' 404 ? 'border-b-2 border-purple-600 text-purple-600' 405 : 'text-purple-600 hover:text-purple-700' 406 }`} 407 > 408 Request Procedure 409 </button> 410 </div> 411 412 {/* View Medical Data Tab */} 413 {activeTab === 'view' && ( 414 <div className="space-y-6"> 415 {/* Diagnoses */} 416 {record.diagnoses && record.diagnoses.length > 0 && ( 417 <div className="bg-white rounded-lg shadow p-6"> 418 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Diagnoses</h3> 419 <div className="space-y-3"> 420 {record.diagnoses.map((diagnosis) => ( 421 <div key={diagnosis.diagnosisId} className="border-l-4 border-purple-500 pl-4 py-2"> 422 <p className="font-normal" style={{ fontSize: '18px' }}>{diagnosis.name}</p> 423 {diagnosis.description && ( 424 <p className="font-normal text-gray-600 text-sm">{diagnosis.description}</p> 425 )} 426 <p className="font-normal text-xs text-gray-500">By: {diagnosis.doctorName}</p> 427 </div> 428 ))} 429 </div> 430 </div> 431 )} 432 433 {/* Symptoms */} 434 {record.symptoms && record.symptoms.length > 0 && ( 435 <div className="bg-white rounded-lg shadow p-6"> 436 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Symptoms</h3> 437 <div className="flex flex-wrap gap-2"> 438 {record.symptoms.map((symptom) => ( 439 <span 440 key={symptom.symptomId} 441 className="bg-yellow-100 text-yellow-800 px-3 py-1 rounded-full text-sm font-normal" 442 > 437 443 {symptom.symptomName} 438 444 </span> 439 ))}440 </div>441 </div>442 )}443 444 {/* Allergies */}445 {record.allergies && record.allergies.length > 0 && (446 <div className="bg-white rounded-lg shadow p-6">447 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Allergies</h3>448 <div className="space-y-3">449 {record.allergies.map((allergy) => (450 <div key={allergy.allergyId} className="border-l-4 border-red-500 pl-4 py-2">451 <p className="font-normal">{allergy.allergyName}</p>452 <p className="font-normal" style={{ fontSize: '14px' }}>445 ))} 446 </div> 447 </div> 448 )} 449 450 {/* Allergies */} 451 {record.allergies && record.allergies.length > 0 && ( 452 <div className="bg-white rounded-lg shadow p-6"> 453 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Allergies</h3> 454 <div className="space-y-3"> 455 {record.allergies.map((allergy) => ( 456 <div key={allergy.allergyId} className="border-l-4 border-red-500 pl-4 py-2"> 457 <p className="font-normal">{allergy.allergyName}</p> 458 <p className="font-normal" style={{ fontSize: '14px' }}> 453 459 <span 454 className="font-normal"455 style={{456 padding: '4px 8px',457 borderRadius: '4px',458 color: 'white',459 fontSize: '12px',460 background: allergy.severity === 'CRITICAL' ? '#dc2626' : allergy.severity === 'HIGH' ? '#ef4444' : allergy.severity === 'MEDIUM' ? '#eab308' : '#22c55e'461 }}460 className="font-normal" 461 style={{ 462 padding: '4px 8px', 463 borderRadius: '4px', 464 color: 'white', 465 fontSize: '12px', 466 background: allergy.severity === 'CRITICAL' ? '#dc2626' : allergy.severity === 'HIGH' ? '#ef4444' : allergy.severity === 'MEDIUM' ? '#eab308' : '#22c55e' 467 }} 462 468 > 463 469 {allergy.severity} Severity 464 470 </span> 465 </p> 466 {allergy.reaction && ( 467 <p className="font-normal text-gray-600 text-sm">Reaction: {allergy.reaction}</p> 468 )} 469 </div> 470 ))} 471 </div> 471 </p> 472 {allergy.reaction && ( 473 <p className="font-normal text-gray-600 text-sm">Reaction: {allergy.reaction}</p> 474 )} 475 </div> 476 ))} 477 </div> 478 </div> 479 )} 480 481 {/* Prescriptions */} 482 {record.prescriptions && record.prescriptions.length > 0 && ( 483 <div className="bg-white rounded-lg shadow p-6"> 484 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Prescriptions</h3> 485 <div className="space-y-3"> 486 {record.prescriptions.map((prescription) => ( 487 <div key={prescription.prescriptionId} className="border-l-4 border-purple-500 pl-4 py-2"> 488 <p className="font-normal">{prescription.medicationName}</p> 489 <p className="font-normal text-sm text-gray-600">Dosage: {prescription.dosage}</p> 490 <p className="font-normal text-sm text-gray-600">Frequency: {prescription.frequency}</p> 491 <p className="font-normal text-sm text-gray-600">Duration: {prescription.duration}</p> 492 </div> 493 ))} 494 </div> 495 </div> 496 )} 497 498 {/* Reports */} 499 {record.reports && record.reports.length > 0 && ( 500 <div className="bg-white rounded-lg shadow p-6"> 501 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Medical Reports</h3> 502 <div className="space-y-3"> 503 {record.reports.map((report) => ( 504 <div key={report.reportId} className="border-l-4 border-green-500 pl-4 py-2"> 505 <p style={{ fontWeight: 'normal' }}>Report from {report.doctorName}</p> 506 <p className="font-normal text-gray-600 text-sm">{report.description}</p> 507 <p className="font-normal text-xs text-gray-500">Date: {report.reportDate}</p> 508 </div> 509 ))} 510 </div> 511 </div> 512 )} 513 514 {/* Lab Results */} 515 {labResults && labResults.length > 0 && ( 516 <div className="bg-white rounded-lg shadow p-6"> 517 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Lab Test Results</h3> 518 <div className="space-y-3"> 519 {labResults.map((result) => ( 520 <div key={result.resultId} className="border-l-4 border-cyan-500 pl-4 py-3 bg-cyan-50 rounded"> 521 <p className="font-normal" style={{ fontSize: '18px', color: '#0891b2' }}>{result.testName}</p> 522 <p className="font-normal text-sm text-gray-700 mt-2">Results: {result.results}</p> 523 <p className="font-normal text-sm text-gray-600">Result Date: {result.resultDate}</p> 524 </div> 525 ))} 526 </div> 527 </div> 528 )} 529 530 {/* Procedure Results */} 531 {procedureResults && procedureResults.length > 0 && ( 532 <div className="bg-white rounded-lg shadow p-6"> 533 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Procedure Results</h3> 534 <div className="space-y-3"> 535 {procedureResults.map((result) => ( 536 <div key={result.resultId} className="border-l-4 border-orange-500 pl-4 py-3 bg-orange-50 rounded"> 537 <p className="font-normal" style={{ fontSize: '18px', color: '#b45309' }}>{result.procedure?.procedureType || 'Procedure'}</p> 538 <p className="font-normal text-sm text-gray-700 mt-2">Outcome: {result.resultDescription}</p> 539 <p className="font-normal text-sm text-gray-600">Result Date: {result.resultDate}</p> 540 </div> 541 ))} 542 </div> 543 </div> 544 )} 545 546 {(!record.diagnoses || record.diagnoses.length === 0) && 547 (!record.symptoms || record.symptoms.length === 0) && 548 (!record.allergies || record.allergies.length === 0) && 549 (!record.reports || record.reports.length === 0) && 550 (!labResults || labResults.length === 0) && 551 (!procedureResults || procedureResults.length === 0) && ( 552 <div className="bg-blue-50 rounded-lg p-6 text-center"> 553 <p className="text-gray-600">No medical data recorded yet</p> 554 </div> 555 )} 472 556 </div> 473 )}474 475 {/* Prescriptions*/}476 {record.prescriptions && record.prescriptions.length > 0&& (557 )} 558 559 {/* Record Diagnosis Tab */} 560 {activeTab === 'diagnosis' && ( 477 561 <div className="bg-white rounded-lg shadow p-6"> 478 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Prescriptions</h3> 479 <div className="space-y-3"> 480 {record.prescriptions.map((prescription) => ( 481 <div key={prescription.prescriptionId} className="border-l-4 border-purple-500 pl-4 py-2"> 482 <p className="font-normal">{prescription.medicationName}</p> 483 <p className="font-normal text-sm text-gray-600">Dosage: {prescription.dosage}</p> 484 <p className="font-normal text-sm text-gray-600">Frequency: {prescription.frequency}</p> 485 <p className="font-normal text-sm text-gray-600">Duration: {prescription.duration}</p> 486 </div> 487 ))} 488 </div> 562 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Record New Diagnosis</h3> 563 <form onSubmit={handleAddDiagnosis} className="space-y-4 max-w-2xl"> 564 <div> 565 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Doctor *</label> 566 {isDoctor ? ( 567 <p className="px-4 py-2 bg-gray-100 rounded-lg text-gray-700"> 568 Dr. {user.firstName} {user.lastName} 569 </p> 570 ) : ( 571 <select 572 value={selectedDoctorId} 573 onChange={(e) => setSelectedDoctorId(e.target.value)} 574 className="w-full px-4 py-2 border rounded-lg" 575 required 576 > 577 <option value="">Select doctor</option> 578 {doctors.map((doc) => ( 579 <option key={doc.doctorId} value={doc.doctorId}> 580 Dr. {doc.firstName} {doc.lastName} 581 </option> 582 ))} 583 </select> 584 )} 585 </div> 586 <div> 587 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Diagnosis *</label> 588 <select 589 value={diagnosisForm.diagnosisId} 590 onChange={(e) => setDiagnosisForm({ ...diagnosisForm, diagnosisId: e.target.value })} 591 className="w-full px-4 py-2 border rounded-lg" 592 required 593 > 594 <option value="">{diagnoses.length === 0 ? 'Loading diagnoses...' : 'Select diagnosis'}</option> 595 {diagnoses && diagnoses.length > 0 && diagnoses.map((diagnosis) => ( 596 <option key={diagnosis.id} value={diagnosis.id}> 597 {diagnosis.name} 598 </option> 599 ))} 600 </select> 601 {diagnoses.length === 0 && ( 602 <p className="text-sm text-gray-500 mt-1">No diagnoses available. Please wait...</p> 603 )} 604 </div> 605 <button 606 type="submit" 607 style={{background: '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => e.currentTarget.style.background = '#7e22ce'} onMouseLeave={(e) => e.currentTarget.style.background = '#9333ea'} 608 > 609 Record Diagnosis 610 </button> 611 </form> 489 612 </div> 490 )}491 492 {/* Reports*/}493 {record.reports && record.reports.length > 0&& (613 )} 614 615 {/* Record Symptoms Tab */} 616 {activeTab === 'symptoms' && ( 494 617 <div className="bg-white rounded-lg shadow p-6"> 495 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Medical Reports</h3> 496 <div className="space-y-3"> 497 {record.reports.map((report) => ( 498 <div key={report.reportId} className="border-l-4 border-green-500 pl-4 py-2"> 499 <p style={{ fontWeight: 'normal' }}>Report from {report.doctorName}</p> 500 <p className="font-normal text-gray-600 text-sm">{report.description}</p> 501 <p className="font-normal text-xs text-gray-500">Date: {report.reportDate}</p> 502 </div> 503 ))} 504 </div> 618 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Record Patient Symptoms</h3> 619 <form onSubmit={handleAddSymptom} className="space-y-4 max-w-2xl"> 620 <div> 621 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Doctor *</label> 622 {isDoctor ? ( 623 <p className="px-4 py-2 bg-gray-100 rounded-lg text-gray-700"> 624 Dr. {user.firstName} {user.lastName} 625 </p> 626 ) : ( 627 <select 628 value={selectedDoctorId} 629 onChange={(e) => setSelectedDoctorId(e.target.value)} 630 className="w-full px-4 py-2 border rounded-lg" 631 required 632 > 633 <option value="">Select doctor</option> 634 {doctors.map((doc) => ( 635 <option key={doc.doctorId} value={doc.doctorId}> 636 Dr. {doc.firstName} {doc.lastName} 637 </option> 638 ))} 639 </select> 640 )} 641 </div> 642 <div> 643 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Symptom *</label> 644 <select 645 value={symptomsForm.symptomId} 646 onChange={(e) => setSymptomsForm({ ...symptomsForm, symptomId: e.target.value })} 647 className="w-full px-4 py-2 border rounded-lg" 648 required 649 > 650 <option value="">Select symptom</option> 651 {symptoms.filter(s => !record.symptoms?.some(rs => rs.symptomId === s.id)).map((symptom) => ( 652 <option key={symptom.id} value={symptom.id}> 653 {symptom.name} 654 </option> 655 ))} 656 </select> 657 </div> 658 <button 659 type="submit" 660 style={{background: '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => e.currentTarget.style.background = '#7e22ce'} onMouseLeave={(e) => e.currentTarget.style.background = '#9333ea'} 661 > 662 Record Symptom 663 </button> 664 </form> 505 665 </div> 506 )}507 508 {/* Lab Results*/}509 {labResults && labResults.length > 0&& (666 )} 667 668 {/* Record Allergies Tab */} 669 {activeTab === 'allergies' && ( 510 670 <div className="bg-white rounded-lg shadow p-6"> 511 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Lab Test Results</h3> 512 <div className="space-y-3"> 513 {labResults.map((result) => ( 514 <div key={result.resultId} className="border-l-4 border-cyan-500 pl-4 py-3 bg-cyan-50 rounded"> 515 <p className="font-normal" style={{ fontSize: '18px', color: '#0891b2' }}>{result.testName}</p> 516 <p className="font-normal text-sm text-gray-700 mt-2">Results: {result.results}</p> 517 <p className="font-normal text-sm text-gray-600">Result Date: {result.resultDate}</p> 518 </div> 519 ))} 520 </div> 671 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Record Patient Allergies</h3> 672 <form onSubmit={handleAddAllergy} className="space-y-4 max-w-2xl"> 673 <div> 674 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Doctor *</label> 675 {isDoctor ? ( 676 <p className="px-4 py-2 bg-gray-100 rounded-lg text-gray-700"> 677 Dr. {user.firstName} {user.lastName} 678 </p> 679 ) : ( 680 <select 681 value={selectedDoctorId} 682 onChange={(e) => setSelectedDoctorId(e.target.value)} 683 className="w-full px-4 py-2 border rounded-lg" 684 required 685 > 686 <option value="">Select doctor</option> 687 {doctors.map((doc) => ( 688 <option key={doc.doctorId} value={doc.doctorId}> 689 Dr. {doc.firstName} {doc.lastName} 690 </option> 691 ))} 692 </select> 693 )} 694 </div> 695 <div> 696 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Allergy *</label> 697 <select 698 value={allergyForm.allergyId} 699 onChange={(e) => setAllergyForm({ ...allergyForm, allergyId: e.target.value })} 700 className="w-full px-4 py-2 border rounded-lg" 701 required 702 > 703 <option value="">Select allergy</option> 704 {allergies.filter(a => !record.allergies?.some(ra => ra.allergyId === a.id)).map((allergy) => ( 705 <option key={allergy.id} value={allergy.id}> 706 {allergy.name} 707 </option> 708 ))} 709 </select> 710 </div> 711 <div> 712 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Severity *</label> 713 <select 714 value={allergyForm.severity} 715 onChange={(e) => setAllergyForm({ ...allergyForm, severity: e.target.value })} 716 className="w-full px-4 py-2 border rounded-lg" 717 > 718 <option value="LOW">Low</option> 719 <option value="MEDIUM">Medium</option> 720 <option value="HIGH">High</option> 721 <option value="CRITICAL">Critical</option> 722 </select> 723 </div> 724 <div> 725 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Reaction</label> 726 <textarea 727 value={allergyForm.reaction} 728 onChange={(e) => setAllergyForm({ ...allergyForm, reaction: e.target.value })} 729 placeholder="Describe the allergic reaction" 730 className="w-full px-4 py-2 border rounded-lg" 731 rows="3" 732 /> 733 </div> 734 <button 735 type="submit" 736 style={{background: '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => e.currentTarget.style.background = '#7e22ce'} onMouseLeave={(e) => e.currentTarget.style.background = '#9333ea'} 737 > 738 Record Allergy 739 </button> 740 </form> 521 741 </div> 522 )}523 524 {/* Procedure Results*/}525 {procedureResults && procedureResults.length > 0&& (742 )} 743 744 {/* Record Prescription Tab */} 745 {activeTab === 'prescription' && ( 526 746 <div className="bg-white rounded-lg shadow p-6"> 527 <h3 className="font-normal" style={{ fontSize: '20px', marginBottom: '16px' }}>Procedure Results</h3> 528 <div className="space-y-3"> 529 {procedureResults.map((result) => ( 530 <div key={result.resultId} className="border-l-4 border-orange-500 pl-4 py-3 bg-orange-50 rounded"> 531 <p className="font-normal" style={{ fontSize: '18px', color: '#b45309' }}>{result.procedure?.procedureType || 'Procedure'}</p> 532 <p className="font-normal text-sm text-gray-700 mt-2">Outcome: {result.resultDescription}</p> 533 <p className="font-normal text-sm text-gray-600">Result Date: {result.resultDate}</p> 534 </div> 535 ))} 536 </div> 747 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Record Prescription</h3> 748 <form onSubmit={handleAddPrescription} className="space-y-4 max-w-2xl"> 749 <div> 750 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Doctor *</label> 751 {isDoctor ? ( 752 <p className="px-4 py-2 bg-gray-100 rounded-lg text-gray-700"> 753 Dr. {user.firstName} {user.lastName} 754 </p> 755 ) : ( 756 <select 757 value={selectedDoctorId} 758 onChange={(e) => setSelectedDoctorId(e.target.value)} 759 className="w-full px-4 py-2 border rounded-lg" 760 required 761 > 762 <option value="">Select doctor</option> 763 {doctors.map((doc) => ( 764 <option key={doc.doctorId} value={doc.doctorId}> 765 Dr. {doc.firstName} {doc.lastName} 766 </option> 767 ))} 768 </select> 769 )} 770 </div> 771 <div> 772 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Medication *</label> 773 <select 774 value={prescriptionForm.prescriptionId} 775 onChange={(e) => 776 setPrescriptionForm({ ...prescriptionForm, prescriptionId: e.target.value }) 777 } 778 className="w-full px-4 py-2 border rounded-lg" 779 required 780 > 781 <option value="">Select medication</option> 782 {prescriptions.map((prescription) => ( 783 <option key={prescription.id} value={prescription.id}> 784 {prescription.name} 785 </option> 786 ))} 787 </select> 788 </div> 789 <div className="grid grid-cols-2 gap-4"> 790 <div> 791 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Dosage *</label> 792 <input 793 type="text" 794 value={prescriptionForm.dosage} 795 onChange={(e) => 796 setPrescriptionForm({ ...prescriptionForm, dosage: e.target.value }) 797 } 798 placeholder="e.g., 500mg" 799 className="w-full px-4 py-2 border rounded-lg" 800 required 801 /> 802 </div> 803 <div> 804 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Frequency *</label> 805 <input 806 type="text" 807 value={prescriptionForm.frequency} 808 onChange={(e) => 809 setPrescriptionForm({ ...prescriptionForm, frequency: e.target.value }) 810 } 811 placeholder="e.g., Twice daily" 812 className="w-full px-4 py-2 border rounded-lg" 813 required 814 /> 815 </div> 816 <div> 817 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Duration *</label> 818 <input 819 type="text" 820 value={prescriptionForm.duration} 821 onChange={(e) => 822 setPrescriptionForm({ ...prescriptionForm, duration: e.target.value }) 823 } 824 placeholder="e.g., 7 days" 825 className="w-full px-4 py-2 border rounded-lg" 826 required 827 /> 828 </div> 829 </div> 830 <div> 831 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Reason for Prescription</label> 832 <textarea 833 value={prescriptionForm.reason} 834 onChange={(e) => setPrescriptionForm({ ...prescriptionForm, reason: e.target.value })} 835 placeholder="Describe why this medication is prescribed" 836 className="w-full px-4 py-2 border rounded-lg" 837 rows="3" 838 /> 839 </div> 840 <button 841 type="submit" 842 style={{background: '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => e.currentTarget.style.background = '#7e22ce'} onMouseLeave={(e) => e.currentTarget.style.background = '#9333ea'} 843 > 844 Record Prescription 845 </button> 846 </form> 537 847 </div> 538 )} 539 540 {(!record.diagnoses || record.diagnoses.length === 0) && 541 (!record.symptoms || record.symptoms.length === 0) && 542 (!record.allergies || record.allergies.length === 0) && 543 (!record.reports || record.reports.length === 0) && 544 (!labResults || labResults.length === 0) && 545 (!procedureResults || procedureResults.length === 0) && ( 546 <div className="bg-blue-50 rounded-lg p-6 text-center"> 547 <p className="text-gray-600">No medical data recorded yet</p> 548 </div> 549 )} 550 </div> 551 )} 552 553 {/* Record Diagnosis Tab */} 554 {activeTab === 'diagnosis' && ( 555 <div className="bg-white rounded-lg shadow p-6"> 556 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Record New Diagnosis</h3> 557 <form onSubmit={handleAddDiagnosis} className="space-y-4 max-w-2xl"> 558 <div> 559 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Doctor *</label> 560 {isDoctor ? ( 561 <p className="px-4 py-2 bg-gray-100 rounded-lg text-gray-700"> 562 Dr. {user.firstName} {user.lastName} 563 </p> 564 ) : ( 565 <select 566 value={selectedDoctorId} 567 onChange={(e) => setSelectedDoctorId(e.target.value)} 568 className="w-full px-4 py-2 border rounded-lg" 569 required 848 )} 849 850 {/* Procedure Request Tab */} 851 {activeTab === 'procedures' && ( 852 <div className="bg-white rounded-lg shadow p-6"> 853 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Request Procedure</h3> 854 <form onSubmit={async (e) => { 855 e.preventDefault(); 856 setError(null); 857 858 if (!procedureForm.procedureId) { 859 setError('Please select a procedure'); 860 return; 861 } 862 863 try { 864 setLoading(true); 865 const doctorId = user.doctorId || 1; 866 867 const request = { 868 patientId: record.patientId, 869 doctorId: parseInt(doctorId), 870 procedureId: parseInt(procedureForm.procedureId), 871 procedureDate: procedureForm.procedureDate, 872 notes: procedureForm.notes, 873 diagnosisId: procedureForm.diagnosisId ? parseInt(procedureForm.diagnosisId) : null, 874 }; 875 876 await procedureService.requestProcedure(request); 877 878 setSuccess('Procedure requested successfully'); 879 setProcedureForm({ 880 procedureId: '', 881 procedureDate: new Date().toISOString().split('T')[0], 882 notes: '', 883 diagnosisId: '', 884 }); 885 886 setTimeout(() => setSuccess(null), 3000); 887 } catch (err) { 888 setError('Failed to request procedure: ' + (err.response?.data?.error || err.message)); 889 } finally { 890 setLoading(false); 891 } 892 }} className="space-y-4"> 893 <div className="grid grid-cols-2 gap-4"> 894 <div> 895 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Procedure *</label> 896 <select 897 value={procedureForm.procedureId} 898 onChange={(e) => setProcedureForm({ ...procedureForm, procedureId: e.target.value })} 899 className="w-full px-4 py-2 border rounded-lg" 900 required 901 > 902 <option value="">Select a procedure</option> 903 {procedures.map((proc) => ( 904 <option key={proc.procedureId} value={proc.procedureId}> 905 {proc.procedureType} (${proc.cost}) 906 </option> 907 ))} 908 </select> 909 </div> 910 <div> 911 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Procedure Date *</label> 912 <input 913 type="date" 914 value={procedureForm.procedureDate} 915 onChange={(e) => setProcedureForm({ ...procedureForm, procedureDate: e.target.value })} 916 className="w-full px-4 py-2 border rounded-lg" 917 required 918 /> 919 </div> 920 </div> 921 <div> 922 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Related Diagnosis (Optional)</label> 923 <select 924 value={procedureForm.diagnosisId} 925 onChange={(e) => setProcedureForm({ ...procedureForm, diagnosisId: e.target.value })} 926 className="w-full px-4 py-2 border rounded-lg" 927 > 928 <option value="">Select diagnosis (optional)</option> 929 {diagnoses.map((diagnosis) => ( 930 <option key={diagnosis.id} value={diagnosis.id}> 931 {diagnosis.name} 932 </option> 933 ))} 934 </select> 935 </div> 936 <div> 937 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Notes</label> 938 <textarea 939 value={procedureForm.notes} 940 onChange={(e) => setProcedureForm({ ...procedureForm, notes: e.target.value })} 941 placeholder="Pre-procedure instructions or special notes" 942 className="w-full px-4 py-2 border rounded-lg" 943 rows="3" 944 /> 945 </div> 946 <button 947 type="submit" 948 disabled={loading} 949 style={{background: loading ? '#9ca3af' : '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => !loading && (e.currentTarget.style.background = '#7e22ce')} onMouseLeave={(e) => !loading && (e.currentTarget.style.background = '#9333ea')} 570 950 > 571 <option value="">Select doctor</option> 572 {doctors.map((doc) => ( 573 <option key={doc.doctorId} value={doc.doctorId}> 574 Dr. {doc.firstName} {doc.lastName} 575 </option> 576 ))} 577 </select> 578 )} 951 {loading ? 'Requesting...' : 'Request Procedure'} 952 </button> 953 </form> 579 954 </div> 580 <div> 581 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Diagnosis *</label> 582 <select 583 value={diagnosisForm.diagnosisId} 584 onChange={(e) => setDiagnosisForm({ ...diagnosisForm, diagnosisId: e.target.value })} 585 className="w-full px-4 py-2 border rounded-lg" 586 required 587 > 588 <option value="">{diagnoses.length === 0 ? 'Loading diagnoses...' : 'Select diagnosis'}</option> 589 {diagnoses && diagnoses.length > 0 && diagnoses.map((diagnosis) => ( 590 <option key={diagnosis.id} value={diagnosis.id}> 591 {diagnosis.name} 592 </option> 593 ))} 594 </select> 595 {diagnoses.length === 0 && ( 596 <p className="text-sm text-gray-500 mt-1">No diagnoses available. Please wait...</p> 597 )} 955 )} 956 957 {/* Lab Test Tab */} 958 {activeTab === 'lab-tests' && ( 959 <div className="bg-white rounded-lg shadow p-6"> 960 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Request Lab Test</h3> 961 <form onSubmit={async (e) => { 962 e.preventDefault(); 963 setError(null); 964 965 if (!labTestForm.testId) { 966 setError('Please select a test'); 967 return; 968 } 969 970 if (!labTestForm.technicianId) { 971 setError('Please select a lab technician'); 972 return; 973 } 974 975 try { 976 setLoading(true); 977 const doctorId = user.doctorId || 1; 978 979 const request = { 980 patientId: record.patientId, 981 medicalRecordId: record.recordId, 982 doctorId: parseInt(doctorId), 983 testId: parseInt(labTestForm.testId), 984 technicianId: parseInt(labTestForm.technicianId), 985 testDate: labTestForm.testDate, 986 notes: labTestForm.notes, 987 }; 988 989 await labService.requestLabTest(request); 990 991 setSuccess('Lab test requested successfully'); 992 setLabTestForm({ 993 testId: '', 994 technicianId: '', 995 testDate: new Date().toISOString().split('T')[0], 996 notes: '', 997 }); 998 999 setTimeout(() => setSuccess(null), 3000); 1000 } catch (err) { 1001 setError('Failed to request lab test: ' + (err.response?.data?.error || err.message)); 1002 } finally { 1003 setLoading(false); 1004 } 1005 }} className="space-y-4"> 1006 <div className="grid grid-cols-2 gap-4"> 1007 <div> 1008 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Test</label> 1009 <select 1010 value={labTestForm.testId} 1011 onChange={(e) => setLabTestForm({ ...labTestForm, testId: e.target.value })} 1012 className="w-full px-4 py-2 border rounded-lg" 1013 required 1014 > 1015 <option value="">Select a test</option> 1016 {labTests.map((test) => ( 1017 <option key={test.testId} value={test.testId}> 1018 {test.testName} (${test.cost}) 1019 </option> 1020 ))} 1021 </select> 1022 </div> 1023 <div> 1024 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Test Date</label> 1025 <input 1026 type="date" 1027 value={labTestForm.testDate} 1028 onChange={(e) => setLabTestForm({ ...labTestForm, testDate: e.target.value })} 1029 className="w-full px-4 py-2 border rounded-lg" 1030 /> 1031 </div> 1032 </div> 1033 <div> 1034 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Lab Technician</label> 1035 <select 1036 value={labTestForm.technicianId} 1037 onChange={(e) => setLabTestForm({ ...labTestForm, technicianId: e.target.value })} 1038 className="w-full px-4 py-2 border rounded-lg" 1039 required 1040 > 1041 <option value="">Select a lab technician</option> 1042 {labTechnicians.map((tech) => ( 1043 <option key={tech.technicianId} value={tech.technicianId}> 1044 {tech.name} {tech.lastname} 1045 </option> 1046 ))} 1047 </select> 1048 </div> 1049 <div> 1050 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Notes</label> 1051 <textarea 1052 value={labTestForm.notes} 1053 onChange={(e) => setLabTestForm({ ...labTestForm, notes: e.target.value })} 1054 placeholder="Additional notes for the lab technician" 1055 className="w-full px-4 py-2 border rounded-lg" 1056 rows="3" 1057 /> 1058 </div> 1059 <button 1060 type="submit" 1061 disabled={loading} 1062 style={{background: loading ? '#9ca3af' : '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => !loading && (e.currentTarget.style.background = '#7e22ce')} onMouseLeave={(e) => !loading && (e.currentTarget.style.background = '#9333ea')} 1063 > 1064 {loading ? 'Requesting...' : 'Request Test'} 1065 </button> 1066 </form> 598 1067 </div> 599 <button 600 type="submit" 601 style={{background: '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => e.currentTarget.style.background = '#7e22ce'} onMouseLeave={(e) => e.currentTarget.style.background = '#9333ea'} 602 > 603 Record Diagnosis 604 </button> 605 </form> 606 </div> 607 )} 608 609 {/* Record Symptoms Tab */} 610 {activeTab === 'symptoms' && ( 611 <div className="bg-white rounded-lg shadow p-6"> 612 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Record Patient Symptoms</h3> 613 <form onSubmit={handleAddSymptom} className="space-y-4 max-w-2xl"> 614 <div> 615 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Doctor *</label> 616 {isDoctor ? ( 617 <p className="px-4 py-2 bg-gray-100 rounded-lg text-gray-700"> 618 Dr. {user.firstName} {user.lastName} 619 </p> 620 ) : ( 621 <select 622 value={selectedDoctorId} 623 onChange={(e) => setSelectedDoctorId(e.target.value)} 624 className="w-full px-4 py-2 border rounded-lg" 625 required 626 > 627 <option value="">Select doctor</option> 628 {doctors.map((doc) => ( 629 <option key={doc.doctorId} value={doc.doctorId}> 630 Dr. {doc.firstName} {doc.lastName} 631 </option> 632 ))} 633 </select> 634 )} 635 </div> 636 <div> 637 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Symptom *</label> 638 <select 639 value={symptomsForm.symptomId} 640 onChange={(e) => setSymptomsForm({ ...symptomsForm, symptomId: e.target.value })} 641 className="w-full px-4 py-2 border rounded-lg" 642 required 643 > 644 <option value="">Select symptom</option> 645 {symptoms.filter(s => !record.symptoms?.some(rs => rs.symptomId === s.id)).map((symptom) => ( 646 <option key={symptom.id} value={symptom.id}> 647 {symptom.name} 648 </option> 649 ))} 650 </select> 651 </div> 652 <button 653 type="submit" 654 style={{background: '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => e.currentTarget.style.background = '#7e22ce'} onMouseLeave={(e) => e.currentTarget.style.background = '#9333ea'} 655 > 656 Record Symptom 657 </button> 658 </form> 659 </div> 660 )} 661 662 {/* Record Allergies Tab */} 663 {activeTab === 'allergies' && ( 664 <div className="bg-white rounded-lg shadow p-6"> 665 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Record Patient Allergies</h3> 666 <form onSubmit={handleAddAllergy} className="space-y-4 max-w-2xl"> 667 <div> 668 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Doctor *</label> 669 {isDoctor ? ( 670 <p className="px-4 py-2 bg-gray-100 rounded-lg text-gray-700"> 671 Dr. {user.firstName} {user.lastName} 672 </p> 673 ) : ( 674 <select 675 value={selectedDoctorId} 676 onChange={(e) => setSelectedDoctorId(e.target.value)} 677 className="w-full px-4 py-2 border rounded-lg" 678 required 679 > 680 <option value="">Select doctor</option> 681 {doctors.map((doc) => ( 682 <option key={doc.doctorId} value={doc.doctorId}> 683 Dr. {doc.firstName} {doc.lastName} 684 </option> 685 ))} 686 </select> 687 )} 688 </div> 689 <div> 690 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Allergy *</label> 691 <select 692 value={allergyForm.allergyId} 693 onChange={(e) => setAllergyForm({ ...allergyForm, allergyId: e.target.value })} 694 className="w-full px-4 py-2 border rounded-lg" 695 required 696 > 697 <option value="">Select allergy</option> 698 {allergies.filter(a => !record.allergies?.some(ra => ra.allergyId === a.id)).map((allergy) => ( 699 <option key={allergy.id} value={allergy.id}> 700 {allergy.name} 701 </option> 702 ))} 703 </select> 704 </div> 705 <div> 706 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Severity *</label> 707 <select 708 value={allergyForm.severity} 709 onChange={(e) => setAllergyForm({ ...allergyForm, severity: e.target.value })} 710 className="w-full px-4 py-2 border rounded-lg" 711 > 712 <option value="LOW">Low</option> 713 <option value="MEDIUM">Medium</option> 714 <option value="HIGH">High</option> 715 <option value="CRITICAL">Critical</option> 716 </select> 717 </div> 718 <div> 719 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Reaction</label> 720 <textarea 721 value={allergyForm.reaction} 722 onChange={(e) => setAllergyForm({ ...allergyForm, reaction: e.target.value })} 723 placeholder="Describe the allergic reaction" 724 className="w-full px-4 py-2 border rounded-lg" 725 rows="3" 726 /> 727 </div> 728 <button 729 type="submit" 730 style={{background: '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => e.currentTarget.style.background = '#7e22ce'} onMouseLeave={(e) => e.currentTarget.style.background = '#9333ea'} 731 > 732 Record Allergy 733 </button> 734 </form> 735 </div> 736 )} 737 738 {/* Record Prescription Tab */} 739 {activeTab === 'prescription' && ( 740 <div className="bg-white rounded-lg shadow p-6"> 741 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Record Prescription</h3> 742 <form onSubmit={handleAddPrescription} className="space-y-4 max-w-2xl"> 743 <div> 744 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Doctor *</label> 745 {isDoctor ? ( 746 <p className="px-4 py-2 bg-gray-100 rounded-lg text-gray-700"> 747 Dr. {user.firstName} {user.lastName} 748 </p> 749 ) : ( 750 <select 751 value={selectedDoctorId} 752 onChange={(e) => setSelectedDoctorId(e.target.value)} 753 className="w-full px-4 py-2 border rounded-lg" 754 required 755 > 756 <option value="">Select doctor</option> 757 {doctors.map((doc) => ( 758 <option key={doc.doctorId} value={doc.doctorId}> 759 Dr. {doc.firstName} {doc.lastName} 760 </option> 761 ))} 762 </select> 763 )} 764 </div> 765 <div> 766 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Medication *</label> 767 <select 768 value={prescriptionForm.prescriptionId} 769 onChange={(e) => 770 setPrescriptionForm({ ...prescriptionForm, prescriptionId: e.target.value }) 771 } 772 className="w-full px-4 py-2 border rounded-lg" 773 required 774 > 775 <option value="">Select medication</option> 776 {prescriptions.map((prescription) => ( 777 <option key={prescription.id} value={prescription.id}> 778 {prescription.name} 779 </option> 780 ))} 781 </select> 782 </div> 783 <div className="grid grid-cols-2 gap-4"> 784 <div> 785 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Dosage *</label> 786 <input 787 type="text" 788 value={prescriptionForm.dosage} 789 onChange={(e) => 790 setPrescriptionForm({ ...prescriptionForm, dosage: e.target.value }) 791 } 792 placeholder="e.g., 500mg" 793 className="w-full px-4 py-2 border rounded-lg" 794 required 795 /> 796 </div> 797 <div> 798 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Frequency *</label> 799 <input 800 type="text" 801 value={prescriptionForm.frequency} 802 onChange={(e) => 803 setPrescriptionForm({ ...prescriptionForm, frequency: e.target.value }) 804 } 805 placeholder="e.g., Twice daily" 806 className="w-full px-4 py-2 border rounded-lg" 807 required 808 /> 809 </div> 810 <div> 811 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Duration *</label> 812 <input 813 type="text" 814 value={prescriptionForm.duration} 815 onChange={(e) => 816 setPrescriptionForm({ ...prescriptionForm, duration: e.target.value }) 817 } 818 placeholder="e.g., 7 days" 819 className="w-full px-4 py-2 border rounded-lg" 820 required 821 /> 822 </div> 823 </div> 824 <div> 825 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Reason for Prescription</label> 826 <textarea 827 value={prescriptionForm.reason} 828 onChange={(e) => setPrescriptionForm({ ...prescriptionForm, reason: e.target.value })} 829 placeholder="Describe why this medication is prescribed" 830 className="w-full px-4 py-2 border rounded-lg" 831 rows="3" 832 /> 833 </div> 834 <button 835 type="submit" 836 style={{background: '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => e.currentTarget.style.background = '#7e22ce'} onMouseLeave={(e) => e.currentTarget.style.background = '#9333ea'} 837 > 838 Record Prescription 839 </button> 840 </form> 841 </div> 842 )} 843 844 {/* Procedure Request Tab */} 845 {activeTab === 'procedures' && ( 846 <div className="bg-white rounded-lg shadow p-6"> 847 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Request Procedure</h3> 848 <form onSubmit={async (e) => { 849 e.preventDefault(); 850 setError(null); 851 852 if (!procedureForm.procedureId) { 853 setError('Please select a procedure'); 854 return; 855 } 856 857 try { 858 setLoading(true); 859 const doctorId = user.doctorId || 1; 860 861 const request = { 862 patientId: record.patientId, 863 doctorId: parseInt(doctorId), 864 procedureId: parseInt(procedureForm.procedureId), 865 procedureDate: procedureForm.procedureDate, 866 notes: procedureForm.notes, 867 diagnosisId: procedureForm.diagnosisId ? parseInt(procedureForm.diagnosisId) : null, 868 }; 869 870 await procedureService.requestProcedure(request); 871 872 setSuccess('Procedure requested successfully'); 873 setProcedureForm({ 874 procedureId: '', 875 procedureDate: new Date().toISOString().split('T')[0], 876 notes: '', 877 diagnosisId: '', 878 }); 879 880 setTimeout(() => setSuccess(null), 3000); 881 } catch (err) { 882 setError('Failed to request procedure: ' + (err.response?.data?.error || err.message)); 883 } finally { 884 setLoading(false); 885 } 886 }} className="space-y-4"> 887 <div className="grid grid-cols-2 gap-4"> 888 <div> 889 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Procedure *</label> 890 <select 891 value={procedureForm.procedureId} 892 onChange={(e) => setProcedureForm({ ...procedureForm, procedureId: e.target.value })} 893 className="w-full px-4 py-2 border rounded-lg" 894 required 895 > 896 <option value="">Select a procedure</option> 897 {procedures.map((proc) => ( 898 <option key={proc.procedureId} value={proc.procedureId}> 899 {proc.procedureType} (${proc.cost}) 900 </option> 901 ))} 902 </select> 903 </div> 904 <div> 905 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Procedure Date *</label> 906 <input 907 type="date" 908 value={procedureForm.procedureDate} 909 onChange={(e) => setProcedureForm({ ...procedureForm, procedureDate: e.target.value })} 910 className="w-full px-4 py-2 border rounded-lg" 911 required 912 /> 913 </div> 914 </div> 915 <div> 916 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Related Diagnosis (Optional)</label> 917 <select 918 value={procedureForm.diagnosisId} 919 onChange={(e) => setProcedureForm({ ...procedureForm, diagnosisId: e.target.value })} 920 className="w-full px-4 py-2 border rounded-lg" 921 > 922 <option value="">Select diagnosis (optional)</option> 923 {diagnoses.map((diagnosis) => ( 924 <option key={diagnosis.id} value={diagnosis.id}> 925 {diagnosis.name} 926 </option> 927 ))} 928 </select> 929 </div> 930 <div> 931 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Notes</label> 932 <textarea 933 value={procedureForm.notes} 934 onChange={(e) => setProcedureForm({ ...procedureForm, notes: e.target.value })} 935 placeholder="Pre-procedure instructions or special notes" 936 className="w-full px-4 py-2 border rounded-lg" 937 rows="3" 938 /> 939 </div> 940 <button 941 type="submit" 942 disabled={loading} 943 style={{background: loading ? '#9ca3af' : '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => !loading && (e.currentTarget.style.background = '#7e22ce')} onMouseLeave={(e) => !loading && (e.currentTarget.style.background = '#9333ea')} 944 > 945 {loading ? 'Requesting...' : 'Request Procedure'} 946 </button> 947 </form> 948 </div> 949 )} 950 951 {/* Lab Test Tab */} 952 {activeTab === 'lab-tests' && ( 953 <div className="bg-white rounded-lg shadow p-6"> 954 <h3 style={{ fontSize: '20px', fontWeight: 'normal', marginBottom: '16px' }}>Request Lab Test</h3> 955 <form onSubmit={async (e) => { 956 e.preventDefault(); 957 setError(null); 958 959 if (!labTestForm.testId) { 960 setError('Please select a test'); 961 return; 962 } 963 964 try { 965 setLoading(true); 966 const doctorId = user.doctorId || 1; 967 968 const request = { 969 patientId: record.patientId, 970 medicalRecordId: record.recordId, 971 doctorId: parseInt(doctorId), 972 testId: parseInt(labTestForm.testId), 973 testDate: labTestForm.testDate, 974 notes: labTestForm.notes, 975 }; 976 977 await labService.requestLabTest(request); 978 979 setSuccess('Lab test requested successfully'); 980 setLabTestForm({ 981 testId: '', 982 testDate: new Date().toISOString().split('T')[0], 983 notes: '', 984 }); 985 986 setTimeout(() => setSuccess(null), 3000); 987 } catch (err) { 988 setError('Failed to request lab test: ' + (err.response?.data?.error || err.message)); 989 } finally { 990 setLoading(false); 991 } 992 }} className="space-y-4"> 993 <div className="grid grid-cols-2 gap-4"> 994 <div> 995 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Test</label> 996 <select 997 value={labTestForm.testId} 998 onChange={(e) => setLabTestForm({ ...labTestForm, testId: e.target.value })} 999 className="w-full px-4 py-2 border rounded-lg" 1000 required 1001 > 1002 <option value="">Select a test</option> 1003 {labTests.map((test) => ( 1004 <option key={test.testId} value={test.testId}> 1005 {test.testName} (${test.cost}) 1006 </option> 1007 ))} 1008 </select> 1009 </div> 1010 <div> 1011 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Test Date</label> 1012 <input 1013 type="date" 1014 value={labTestForm.testDate} 1015 onChange={(e) => setLabTestForm({ ...labTestForm, testDate: e.target.value })} 1016 className="w-full px-4 py-2 border rounded-lg" 1017 /> 1018 </div> 1019 </div> 1020 <div> 1021 <label style={{ fontWeight: 'normal' }} className="block text-sm mb-2">Notes</label> 1022 <textarea 1023 value={labTestForm.notes} 1024 onChange={(e) => setLabTestForm({ ...labTestForm, notes: e.target.value })} 1025 placeholder="Additional notes for the lab technician" 1026 className="w-full px-4 py-2 border rounded-lg" 1027 rows="3" 1028 /> 1029 </div> 1030 <button 1031 type="submit" 1032 disabled={loading} 1033 style={{background: loading ? '#9ca3af' : '#9333ea', color: 'white', padding: '6px 14px', borderRadius: '6px', border: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: '600'}} onMouseEnter={(e) => !loading && (e.currentTarget.style.background = '#7e22ce')} onMouseLeave={(e) => !loading && (e.currentTarget.style.background = '#9333ea')} 1034 > 1035 {loading ? 'Requesting...' : 'Request Test'} 1036 </button> 1037 </form> 1038 </div> 1039 )} 1040 </div> 1068 )} 1069 </div> 1041 1070 ); 1042 1071 }
Note:
See TracChangeset
for help on using the changeset viewer.
