diff --git a/app/Controllers/Api/v1/DoctorApi.php b/app/Controllers/Api/v1/DoctorApi.php index 012914a..1391c76 100644 --- a/app/Controllers/Api/v1/DoctorApi.php +++ b/app/Controllers/Api/v1/DoctorApi.php @@ -400,19 +400,43 @@ class DoctorApi extends BaseController public function ipdList(int $docId) { $db = db_connect(); - $builder = $db->table('ipd_master ipd') - ->select('ipd.*, p.p_fname as fname, p.p_code as uhid, p.mphone1, p.gender, p.age, b.bed_code, b.bed_number, w.ward_name') - ->join('patient_master p', 'p.id = ipd.p_id', 'left') - ->join('bed_master b', 'b.id = ipd.bed_id', 'left') - ->join('ward_master w', 'w.id = b.ward_id', 'left') - ->where('ipd.status', 'admitted') - ->orderBy('ipd.id', 'DESC'); + helper('common'); - if ($docId > 0 && $db->fieldExists('doc_id', 'ipd_master')) { - $builder->where('ipd.doc_id', $docId); + $sql = "SELECT ipd.id as ipd_id, ipd.ipd_code, ipd.p_id, ipd.r_doc_id, ipd.r_doc_name, ipd.register_date, ipd.problem, + p.p_fname as fname, p.p_code as uhid, p.mphone1, p.gender, p.age, p.age_in_month, p.estimate_dob, p.dob, + b.bed_code, b.bed_number, w.ward_name + FROM ipd_master ipd + JOIN patient_master p ON p.id = ipd.p_id + LEFT JOIN bed_master b ON b.id = ipd.bed_no + LEFT JOIN ward_master w ON w.id = b.ward_id + WHERE ipd.ipd_status = 0"; + + if ($docId > 0) { + $sql .= " AND (ipd.r_doc_id = " . (int) $docId . " OR ipd.r_doc_id IS NULL OR ipd.r_doc_id = 0)"; } - $patients = $builder->get()->getResultArray(); + $sql .= " ORDER BY ipd.id DESC"; + + $query = $db->query($sql); + $patients = $query->getResultArray(); + + foreach ($patients as &$r) { + $ageDisplay = 'N/A'; + if (function_exists('get_age_1')) { + $ageDisplay = get_age_1($r['dob'] ?? null, $r['age'] ?? '', $r['age_in_month'] ?? '', $r['estimate_dob'] ?? ''); + } elseif (! empty($r['age'])) { + $ageDisplay = $r['age'] . ' Year'; + } elseif (! empty($r['dob']) && $r['dob'] !== '0000-00-00') { + try { + $ageDisplay = date_diff(date_create($r['dob']), date_create('today'))->y . ' Year'; + } catch (\Throwable $e) {} + } + + $r['age_display'] = $ageDisplay; + $r['gender_label'] = ((int)($r['gender'] ?? 1) === 1) ? 'Male' : 'Female'; + $r['patient_display_name'] = $r['fname'] ?? 'Patient'; + $r['bed_label'] = ! empty($r['ward_name']) ? ($r['ward_name'] . ' - Bed ' . ($r['bed_number'] ?? $r['bed_code'] ?? '')) : 'General Ward'; + } return $this->response->setJSON([ 'status' => 1, diff --git a/public/App/Doctor/index.html b/public/App/Doctor/index.html index 83678ab..38fe60d 100644 --- a/public/App/Doctor/index.html +++ b/public/App/Doctor/index.html @@ -136,7 +136,8 @@ // Active Workspace state const [activePatient, setActivePatient] = useState(null); const [activeOpd, setActiveOpd] = useState(null); - const [workspaceData, setWorkspaceData] = useState([]); + const [workspaceEntries, setWorkspaceEntries] = useState([]); + const [newTreatmentNote, setNewTreatmentNote] = useState(''); const [emrTab, setEmrTab] = useState('vitals'); const [installPrompt, setInstallPrompt] = useState(null); @@ -343,6 +344,46 @@ setActiveOpd(null); }; + const openIpdWorkspace = async (patient) => { + setActivePatient(patient); + try { + const res = await fetch(`/api/v1/doctor/ipd/workspace/${patient.ipd_id}`); + const json = await res.json(); + if (json.status === 1) { + setWorkspaceEntries(json.entries || []); + } + } catch (err) { + console.error('Failed to load IPD workspace', err); + } + }; + + const handleSaveTreatmentNote = async () => { + if (!activePatient || !newTreatmentNote.trim()) return; + + try { + const body = new URLSearchParams(); + body.append('doctor_id', authenticatedDoctor ? authenticatedDoctor.id : 0); + body.append('doctor_name', authenticatedDoctor ? authenticatedDoctor.name : 'Doctor'); + body.append('treatment_text', newTreatmentNote); + + const res = await fetch(`/api/v1/doctor/ipd/treatment/save/${activePatient.ipd_id}`, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: body.toString() + }); + const json = await res.json(); + if (json.status === 1) { + alert(json.message || 'Clinical treatment note saved successfully!'); + setNewTreatmentNote(''); + openIpdWorkspace(activePatient); + } else { + alert(json.message || 'Failed to save treatment note'); + } + } catch (err) { + alert('Error saving treatment note'); + } + }; + const openOpdConsultation = async (app) => { setActiveOpd(app); try { @@ -449,6 +490,14 @@ return matchesFilter && matchesSearch; }); + const filteredIpdPatients = ipdPatients.filter(pat => { + const q = searchQuery.toLowerCase(); + const name = (pat.patient_display_name || pat.fname || '').toLowerCase(); + const uhid = (pat.uhid || '').toLowerCase(); + const ipdCode = (pat.ipd_code || '').toLowerCase(); + return searchQuery === '' || name.includes(q) || uhid.includes(q) || ipdCode.includes(q); + }); + // ------------------------------------------------------------- // RENDER: LOCK SCREEN (PIN AUTHENTICATION) // ------------------------------------------------------------- @@ -554,7 +603,7 @@
| Status | +IPD Code | +Admitted Patient | +Ward & Bed | +UHID | +Admitted Date | +Action | +
|---|---|---|---|---|---|---|
| + + No Admitted IPD Patients found for Dr. {authenticatedDoctor.name}. + | +||||||
| Admitted | +{pat.ipd_code} | +
+ {pat.patient_display_name}
+ ({pat.age_display} / {pat.gender_label})
+ |
+ {pat.bed_label} | +{pat.uhid} |
+ {pat.register_date || 'Today'} | +
+ |
+
No bedside log entries recorded yet.
+ ) : ( + workspaceEntries.map(e => ( +