Spaces:
Sleeping
Sleeping
File size: 8,180 Bytes
095c768 6df1c09 e75450b 6df1c09 e1b176b 6df1c09 e75450b 6df1c09 e75450b 6df1c09 095c768 6df1c09 e1b176b 6df1c09 e75450b 6df1c09 e75450b 6df1c09 e75450b 6df1c09 e75450b 6df1c09 e1b176b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
import { useState, useEffect } from 'react';
import { XIcon } from 'lucide-react';
// Static defaults for fields requested to be static. Change these constants to update the values shown.
const DEFAULT_PATIENT_ID = '41334';
const DEFAULT_PHYSICIAN = 'Rajesh Venugopal';
const DEFAULT_FACILITY = 'Multi-Lab Speciality';
interface ReportModalProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (formData: FormData) => void;
analysisId: string;
analysisSummaryJson: string;
}
export interface ReportFormData {
patient_id: string;
exam_date: string;
metadata: {
physician: string;
facility: string;
clinical_history?: string;
};
notes?: string;
analysis_id: string;
}
export function ReportModal({ isOpen, onClose, onSubmit, analysisId, analysisSummaryJson }: ReportModalProps) {
const [formData, setFormData] = useState<ReportFormData>({
patient_id: DEFAULT_PATIENT_ID,
exam_date: new Date().toISOString().split('T')[0],
metadata: {
physician: DEFAULT_PHYSICIAN,
facility: DEFAULT_FACILITY,
clinical_history: '',
},
notes: '',
analysis_id: analysisId,
});
// Keep internal form state in sync when the parent passes a new analysisId
useEffect(() => {
setFormData(prev => ({ ...prev, analysis_id: analysisId }));
}, [analysisId]);
if (!isOpen) return null;
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// Build FormData for FastAPI endpoint
const payload = new FormData();
payload.append("patient_id", formData.patient_id);
payload.append("exam_date", formData.exam_date);
payload.append("metadata", JSON.stringify(formData.metadata));
payload.append("notes", formData.notes || "");
payload.append("analysis_id", formData.analysis_id);
payload.append("analysis_summary", analysisSummaryJson);
// Pass the FormData object to the parent onSubmit
onSubmit(payload);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
if (name.startsWith('metadata.')) {
const field = name.split('.')[1];
setFormData(prev => ({
...prev,
metadata: {
...prev.metadata,
[field]: value,
},
}));
} else {
setFormData(prev => ({
...prev,
[name]: value,
}));
}
};
return (
<div className="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
<div className="bg-white rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<div className="p-6 space-y-6">
<div className="flex items-center justify-between border-b pb-3">
<h2 className="text-2xl font-semibold text-gray-900">Generate Medical Report</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-500"
>
<XIcon className="w-6 h-6" />
</button>
</div>
<form onSubmit={handleSubmit} className="space-y-6">
{/* Patient Information */}
<div className="space-y-4">
<h3 className="text-lg font-medium text-gray-900">Patient Information</h3>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div>
<label htmlFor="patient_id" className="block text-sm font-medium text-gray-700">
Patient ID *
</label>
<input
required
type="text"
name="patient_id"
id="patient_id"
value={formData.patient_id}
onChange={handleChange}
readOnly
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
/>
</div>
<div>
<label htmlFor="exam_date" className="block text-sm font-medium text-gray-700">
Exam Date *
</label>
<input
required
type="date"
name="exam_date"
id="exam_date"
value={formData.exam_date}
onChange={handleChange}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
/>
</div>
</div>
</div>
{/* Slide Metadata */}
<div className="space-y-4">
<h3 className="text-lg font-medium text-gray-900">Slide Metadata</h3>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div>
<label htmlFor="metadata.physician" className="block text-sm font-medium text-gray-700">
Physician Name *
</label>
<input
required
type="text"
name="metadata.physician"
id="metadata.physician"
value={formData.metadata.physician}
onChange={handleChange}
readOnly
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
/>
</div>
<div>
<label htmlFor="metadata.facility" className="block text-sm font-medium text-gray-700">
Facility *
</label>
<input
required
type="text"
name="metadata.facility"
id="metadata.facility"
value={formData.metadata.facility}
onChange={handleChange}
readOnly
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
/>
</div>
<div>
<label htmlFor="metadata.clinical_history" className="block text-sm font-medium text-gray-700">
Clinical History
</label>
<input
type="text"
name="metadata.clinical_history"
id="metadata.clinical_history"
value={formData.metadata.clinical_history}
onChange={handleChange}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
/>
</div>
</div>
</div>
{/* Notes */}
<div className="space-y-4">
<h3 className="text-lg font-medium text-gray-900">Doctor's Notes</h3>
<textarea
name="notes"
id="notes"
rows={4}
value={formData.notes}
onChange={handleChange}
placeholder="Add any additional notes or observations..."
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
/>
</div>
{/* Actions */}
<div className="flex items-center justify-end space-x-3 pt-4 border-t">
<button
type="button"
onClick={onClose}
className="px-4 py-2 text-sm font-medium text-gray-700 hover:text-gray-500"
>
Cancel
</button>
<button
type="submit"
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Generate Report
</button>
</div>
</form>
</div>
</div>
</div>
);
}
|