diff --git a/app/Controllers/Ipd_discharge.php b/app/Controllers/Ipd_discharge.php index 86fef95..66e6e6f 100644 --- a/app/Controllers/Ipd_discharge.php +++ b/app/Controllers/Ipd_discharge.php @@ -2693,6 +2693,17 @@ class Ipd_discharge extends BaseController continue; } + if ($rowRemark !== '' && ($rowRemark[0] === '{' || $rowRemark[0] === '[')) { + $decoded = json_decode($rowRemark, true); + if (is_array($decoded)) { + $parts = []; + if (! empty($decoded['duration'])) $parts[] = (string) $decoded['duration']; + if (! empty($decoded['frequency'])) $parts[] = (string) $decoded['frequency']; + if (! empty($decoded['severity'])) $parts[] = (string) $decoded['severity']; + $rowRemark = implode(', ', $parts); + } + } + if ($report !== '' && $rowRemark !== '') { $lines[] = esc($report) . ' ' . esc($rowRemark) . ''; } elseif ($report !== '') { @@ -2714,6 +2725,38 @@ class Ipd_discharge extends BaseController return '

' . esc($title) . ' :
' . implode('
', $lines) . '

'; } + private function getDischargeComplaintRows(int $ipdId): array + { + $rawRows = $this->byIpdRows('ipd_discharge_complaint', ['id', 'comp_report', 'comp_remark'], 'id ASC', $ipdId); + $out = []; + foreach ($rawRows as $row) { + $id = (int) ($row['id'] ?? 0); + $term = (string) ($row['comp_report'] ?? ''); + $rawRemark = (string) ($row['comp_remark'] ?? ''); + $freq = ''; + $sev = ''; + $dur = $rawRemark; + if ($rawRemark !== '' && ($rawRemark[0] === '{' || $rawRemark[0] === '[')) { + $decoded = json_decode($rawRemark, true); + if (is_array($decoded)) { + $dur = (string) ($decoded['duration'] ?? ''); + $freq = (string) ($decoded['frequency'] ?? ''); + $sev = (string) ($decoded['severity'] ?? ''); + } + } + $out[] = [ + 'id' => $id, + 'term' => $term, + 'frequency' => $freq, + 'severity' => $sev, + 'duration' => $dur, + 'date' => '', + ]; + } + + return $out; + } + private function sanitizeComplaintNarrativeRemark(string $remark): string { $remark = trim($remark); @@ -6276,7 +6319,7 @@ class Ipd_discharge extends BaseController && ($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json') && in_array( (string) ($this->request->getPost('action') ?? ''), - ['add_drug', 'remove_drug', 'remove_all_drugs', 'add_course', 'remove_course', 'apply_rx_group'], + ['add_drug', 'remove_drug', 'remove_all_drugs', 'add_course', 'remove_course', 'apply_rx_group', 'add_complaint', 'update_complaint', 'remove_complaint'], true ); @@ -6382,8 +6425,22 @@ class Ipd_discharge extends BaseController } if ($action === 'add_complaint') { - $complaintName = trim((string) ($this->request->getPost('new_complaint_name') ?? '')); + $complaintName = trim((string) ($this->request->getPost('complaint_term') ?? $this->request->getPost('new_complaint_name') ?? '')); + $complaintDuration = trim((string) ($this->request->getPost('complaint_duration') ?? '')); + $complaintFreq = trim((string) ($this->request->getPost('complaint_frequency') ?? '')); + $complaintSev = trim((string) ($this->request->getPost('complaint_severity') ?? '')); $complaintRemarkRow = trim((string) ($this->request->getPost('new_complaint_remark') ?? '')); + + if ($complaintFreq !== '' || $complaintSev !== '') { + $complaintRemarkRow = json_encode([ + 'duration' => $complaintDuration, + 'frequency' => $complaintFreq, + 'severity' => $complaintSev, + ], JSON_UNESCAPED_UNICODE) ?: $complaintDuration; + } elseif ($complaintDuration !== '') { + $complaintRemarkRow = $complaintDuration; + } + $complaintRemarkText = trim((string) ($this->request->getPost('complaint_remark') ?? '')); $painValue = trim((string) ($this->request->getPost('pain_value') ?? '')); if (! in_array($painValue, ['0', '1', '2', '3', '4'], true)) { @@ -6404,10 +6461,11 @@ class Ipd_discharge extends BaseController } $savedAny = (bool) $this->db->table('ipd_discharge_complaint')->insert($insert); + $ajaxRowId = $savedAny ? (int) ($this->db->insertID() ?? 0) : 0; $notice = $savedAny ? 'Complaint row added.' : 'Unable to add complaint row.'; $noticeType = $savedAny ? 'success' : 'warning'; - if ($this->tableHasColumns('ipd_discharge_complaint_remark', ['ipd_id'])) { + if ($this->tableHasColumns('ipd_discharge_complaint_remark', ['ipd_id']) && $complaintRemarkText !== '') { $savedAny = $this->upsertByIpd('ipd_discharge_complaint_remark', $ipdId, [ 'comp_report' => $this->buildComplaintMetaPayload(['pain_value' => $painValue]), 'comp_remark' => $complaintRemarkText, @@ -6418,6 +6476,41 @@ class Ipd_discharge extends BaseController $notice = 'Enter complaint name before adding.'; $noticeType = 'warning'; } + } elseif ($action === 'update_complaint') { + $complaintId = (int) ($this->request->getPost('complaint_row_id') ?? 0); + $complaintName = trim((string) ($this->request->getPost('complaint_term') ?? $this->request->getPost('new_complaint_name') ?? '')); + $complaintDuration = trim((string) ($this->request->getPost('complaint_duration') ?? '')); + $complaintFreq = trim((string) ($this->request->getPost('complaint_frequency') ?? '')); + $complaintSev = trim((string) ($this->request->getPost('complaint_severity') ?? '')); + + if ($complaintFreq !== '' || $complaintSev !== '') { + $remarkPayload = json_encode([ + 'duration' => $complaintDuration, + 'frequency' => $complaintFreq, + 'severity' => $complaintSev, + ], JSON_UNESCAPED_UNICODE) ?: $complaintDuration; + } else { + $remarkPayload = $complaintDuration; + } + + if ($complaintId > 0 && $complaintName !== '' && $this->tableHasColumns('ipd_discharge_complaint', ['id', 'ipd_id'])) { + $updateData = [ + 'comp_report' => $complaintName, + 'comp_remark' => $remarkPayload, + 'update_by' => $userLabel, + ]; + $this->db->table('ipd_discharge_complaint') + ->where('id', $complaintId) + ->where('ipd_id', $ipdId) + ->update($updateData); + $savedAny = true; + $ajaxRowId = $complaintId; + $notice = 'Complaint updated successfully.'; + $noticeType = 'success'; + } else { + $notice = 'Unable to update complaint: invalid ID or missing name.'; + $noticeType = 'warning'; + } } elseif ($action === 'remove_complaint') { $removeId = (int) ($this->request->getPost('complaint_remove_id') ?? 0); $complaintRemarkText = trim((string) ($this->request->getPost('complaint_remark') ?? '')); @@ -6430,10 +6523,11 @@ class Ipd_discharge extends BaseController ->where('id', $removeId) ->where('ipd_id', $ipdId) ->delete(); + $ajaxRowId = $removeId; $notice = $savedAny ? 'Complaint row removed.' : 'Unable to remove complaint row.'; $noticeType = $savedAny ? 'success' : 'warning'; - if ($this->tableHasColumns('ipd_discharge_complaint_remark', ['ipd_id'])) { + if ($this->tableHasColumns('ipd_discharge_complaint_remark', ['ipd_id']) && $complaintRemarkText !== '') { $savedAny = $this->upsertByIpd('ipd_discharge_complaint_remark', $ipdId, [ 'comp_report' => $this->buildComplaintMetaPayload(['pain_value' => $painValue]), 'comp_remark' => $complaintRemarkText, @@ -6599,7 +6693,8 @@ class Ipd_discharge extends BaseController } } - if (($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json') && in_array($action, ['add_surgery', 'remove_surgery', 'add_procedure', 'remove_procedure', 'add_diagnosis', 'remove_diagnosis'], true)) { + if (($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json') && in_array($action, ['add_complaint', 'update_complaint', 'remove_complaint', 'add_surgery', 'remove_surgery', 'add_procedure', 'remove_procedure', 'add_diagnosis', 'remove_diagnosis'], true)) { + $complaintRows = $this->getDischargeComplaintRows($ipdId); $surgeryRows = $this->byIpdRows('ipd_discharge_surgery', ['id', 'surgery_name', 'surgery_date', 'surgery_remark'], 'id ASC', $ipdId); $procedureRows = $this->byIpdRows('ipd_discharge_procedure', ['id', 'procedure_name', 'procedure_date', 'procedure_remark'], 'id ASC', $ipdId); $diagnosisRows = $this->byIpdRows('ipd_discharge_diagnosis', ['id', 'comp_report', 'comp_remark'], 'id ASC', $ipdId); @@ -6610,6 +6705,7 @@ class Ipd_discharge extends BaseController 'noticeType' => $noticeType ?? 'info', 'row_id' => $ajaxRowId ?? 0, 'row_source' => $ajaxRowSource ?? 'legacy', + 'complaintRows' => $complaintRows, 'surgeryRows' => $surgeryRows, 'procedureRows' => $procedureRows, 'diagnosisRows' => $diagnosisRows, @@ -7187,11 +7283,23 @@ class Ipd_discharge extends BaseController } $duration = trim((string) ($row['duration'] ?? '')); + $freq = trim((string) ($row['frequency'] ?? '')); + $sev = trim((string) ($row['severity'] ?? '')); $rowId = (int) ($row['id'] ?? 0); + if ($freq !== '' || $sev !== '') { + $remarkPayload = json_encode([ + 'duration' => $duration, + 'frequency' => $freq, + 'severity' => $sev, + ], JSON_UNESCAPED_UNICODE) ?: $duration; + } else { + $remarkPayload = $duration; + } + $commonData = [ 'comp_report' => $term, - 'comp_remark' => $duration, + 'comp_remark' => $remarkPayload, 'update_by' => $userLabel, ]; if ($this->db->fieldExists('order_id', 'ipd_discharge_complaint')) { @@ -7752,6 +7860,7 @@ class Ipd_discharge extends BaseController 'row_id' => $ajaxRowId, 'row_source' => $ajaxRowSource, 'drugRows' => $drugRows, + 'complaintRows' => $this->getDischargeComplaintRows($ipdId), 'csrfName' => csrf_token(), 'csrfHash' => csrf_hash(), ]); diff --git a/app/Views/billing/ipd/discharge_create.php b/app/Views/billing/ipd/discharge_create.php index f29f5cb..86a5c8c 100644 --- a/app/Views/billing/ipd/discharge_create.php +++ b/app/Views/billing/ipd/discharge_create.php @@ -630,7 +630,7 @@ $historyFields = [ Frequency Severity Duration - + Action @@ -646,7 +646,7 @@ $historyFields = [ style="display:none;position:absolute;left:0;right:0;top:100%;z-index:1060;max-height:260px;overflow-y:auto;"> - + @@ -665,12 +665,24 @@ $historyFields = [ $complaintSeedRows = []; if (isset($complaint_rows) && is_array($complaint_rows)) { foreach ($complaint_rows as $row) { + $rawRemark = (string) ($row['comp_remark'] ?? ''); + $freq = ''; + $sev = ''; + $dur = $rawRemark; + if ($rawRemark !== '' && ($rawRemark[0] === '{' || $rawRemark[0] === '[')) { + $decoded = json_decode($rawRemark, true); + if (is_array($decoded)) { + $dur = (string) ($decoded['duration'] ?? ''); + $freq = (string) ($decoded['frequency'] ?? ''); + $sev = (string) ($decoded['severity'] ?? ''); + } + } $complaintSeedRows[] = [ 'id' => (int) ($row['id'] ?? 0), 'term' => (string) ($row['comp_report'] ?? ''), - 'frequency' => '', - 'severity' => '', - 'duration' => (string) ($row['comp_remark'] ?? ''), + 'frequency' => $freq, + 'severity' => $sev, + 'duration' => $dur, 'date' => '', ]; } @@ -680,6 +692,7 @@ $historyFields = [ + @@ -2302,9 +2315,10 @@ $historyFields = [ nameInput.name = 'complaint_term[]'; nameInput.className = 'form-control form-control-sm complaint-name-input'; nameInput.value = item.term || ''; - nameInput.placeholder = 'Complaint…'; + nameInput.placeholder = 'Complaint (Type to search)…'; nameInput.style.fontSize = '.82rem'; nameInput.setAttribute('data-idx', idx); + nameInput.setAttribute('autocomplete', 'off'); nameInput.addEventListener('input', function() { selectedDischargeComplaints[idx].term = this.value; syncDischargeComplaintJsonField(); @@ -2323,6 +2337,7 @@ $historyFields = [ freqInput.placeholder = 'daily…'; freqInput.style.fontSize = '.82rem'; freqInput.setAttribute('data-idx', idx); + freqInput.setAttribute('autocomplete', 'off'); freqInput.addEventListener('input', function() { selectedDischargeComplaints[idx].frequency = this.value; syncDischargeComplaintJsonField(); @@ -2341,6 +2356,7 @@ $historyFields = [ sevInput.placeholder = 'mild…'; sevInput.style.fontSize = '.82rem'; sevInput.setAttribute('data-idx', idx); + sevInput.setAttribute('autocomplete', 'off'); sevInput.addEventListener('input', function() { selectedDischargeComplaints[idx].severity = this.value; syncDischargeComplaintJsonField(); @@ -2359,6 +2375,7 @@ $historyFields = [ durInput.placeholder = '2 days…'; durInput.style.fontSize = '.82rem'; durInput.setAttribute('data-idx', idx); + durInput.setAttribute('autocomplete', 'off'); durInput.addEventListener('input', function() { selectedDischargeComplaints[idx].duration = this.value; syncDischargeComplaintJsonField(); @@ -2372,21 +2389,37 @@ $historyFields = [ idInput.value = parseInt(item.id || 0, 10) || 0; tr.appendChild(idInput); - // Remove button + // Action column with Update and Remove buttons var td6 = document.createElement('td'); - td6.className = 'p-1 text-center'; + td6.className = 'p-1 text-center text-nowrap'; + + var updateBtn = document.createElement('button'); + updateBtn.type = 'button'; + updateBtn.className = 'btn btn-sm btn-outline-success btn-update-complaint py-0 px-2 me-1'; + updateBtn.title = 'Save / Update this complaint'; + updateBtn.style.fontSize = '.78rem'; + updateBtn.style.height = '26px'; + updateBtn.setAttribute('data-idx', idx); + updateBtn.innerHTML = 'Update'; + updateBtn.addEventListener('click', function() { + saveDischargeComplaintRow(idx, $(this)); + }); + td6.appendChild(updateBtn); + var removeBtn = document.createElement('button'); removeBtn.type = 'button'; - removeBtn.className = 'btn btn-sm text-danger p-0'; + removeBtn.className = 'btn btn-sm btn-outline-danger btn-remove-complaint p-0'; + removeBtn.title = 'Remove this complaint'; + removeBtn.style.width = '24px'; + removeBtn.style.height = '26px'; removeBtn.style.lineHeight = '1'; + removeBtn.style.fontSize = '1rem'; + removeBtn.setAttribute('data-idx', idx); removeBtn.innerHTML = '×'; removeBtn.addEventListener('click', function() { - selectedDischargeComplaints.splice(idx, 1); - renderDischargeComplaintTable(); - setComplaintStatus('Complaint removed.', 'success'); + removeDischargeComplaintRow(idx, $(this)); }); td6.appendChild(removeBtn); - tr.appendChild(td6); tbody.appendChild(tr); }); @@ -2394,6 +2427,110 @@ $historyFields = [ syncDischargeComplaintJsonField(); } + function saveDischargeComplaintRow(idx, $btn) { + var item = selectedDischargeComplaints[idx]; + if (!item) return; + + // Sync latest values from inputs in this row + var $tr = $('#discharge_complaint_tbody tr[data-idx="' + idx + '"]'); + if ($tr.length) { + var termVal = ($tr.find('.complaint-name-input').val() || '').trim(); + var freqVal = ($tr.find('.complaint-freq-input').val() || '').trim(); + var sevVal = ($tr.find('.complaint-sev-input').val() || '').trim(); + var durVal = ($tr.find('.complaint-dur-input').val() || '').trim(); + item.term = termVal; + item.frequency = freqVal; + item.severity = sevVal; + item.duration = durVal; + } + + if (!item.term) { + setComplaintStatus('Please enter or select a complaint name.', 'error'); + $tr.find('.complaint-name-input').trigger('focus'); + return; + } + + var form = document.getElementById('section-complaints') + ? document.getElementById('section-complaints').closest('form') + : document.querySelector('form'); + var csrf = getCsrfPair(form); + var isUpdate = parseInt(item.id || 0, 10) > 0; + var payload = { + action: isUpdate ? 'update_complaint' : 'add_complaint', + complaint_row_id: parseInt(item.id || 0, 10), + complaint_term: item.term, + complaint_frequency: item.frequency, + complaint_severity: item.severity, + complaint_duration: item.duration, + ajax_mode: 'json' + }; + payload[csrf.name] = csrf.value; + + var origHtml = $btn ? $btn.html() : ''; + if ($btn) $btn.prop('disabled', true).html(''); + + $.post($(form).attr('action') || window.location.href, payload, function(data) { + updateFormCsrf(form, data); + if ($btn) $btn.prop('disabled', false).html(origHtml); + + if (data && (data.update === 1 || data.update === true)) { + if (data.row_id && parseInt(data.row_id, 10) > 0) { + selectedDischargeComplaints[idx].id = parseInt(data.row_id, 10); + $tr.find('input[name="complaint_row_id[]"]').val(data.row_id); + } + syncDischargeComplaintJsonField(); + setComplaintStatus(data.notice || 'Complaint updated successfully.', 'success'); + if ($btn) { + $btn.removeClass('btn-outline-success').addClass('btn-success').html('Saved'); + setTimeout(function() { + $btn.removeClass('btn-success').addClass('btn-outline-success').html('Update'); + }, 1200); + } + } else { + setComplaintStatus((data && data.notice) ? data.notice : 'Unable to save complaint.', 'error'); + } + }, 'json').fail(function() { + if ($btn) $btn.prop('disabled', false).html(origHtml); + setComplaintStatus('Network error while saving complaint.', 'error'); + }); + } + + function removeDischargeComplaintRow(idx, $btn) { + var item = selectedDischargeComplaints[idx]; + if (!item) return; + + var rowId = parseInt(item.id || 0, 10); + if (rowId > 0) { + var form = document.getElementById('section-complaints') + ? document.getElementById('section-complaints').closest('form') + : document.querySelector('form'); + var csrf = getCsrfPair(form); + var payload = { + action: 'remove_complaint', + complaint_remove_id: rowId, + ajax_mode: 'json' + }; + payload[csrf.name] = csrf.value; + + if ($btn) $btn.prop('disabled', true).html(''); + + $.post($(form).attr('action') || window.location.href, payload, function(data) { + updateFormCsrf(form, data); + selectedDischargeComplaints.splice(idx, 1); + renderDischargeComplaintTable(); + setComplaintStatus((data && data.notice) ? data.notice : 'Complaint removed.', 'success'); + }, 'json').fail(function() { + selectedDischargeComplaints.splice(idx, 1); + renderDischargeComplaintTable(); + setComplaintStatus('Complaint removed from list.', 'success'); + }); + } else { + selectedDischargeComplaints.splice(idx, 1); + renderDischargeComplaintTable(); + setComplaintStatus('Complaint removed.', 'success'); + } + } + // Quick Autotext Chips function renderDischargeRecentChips() { var $box = $('#discharge_recent_complaint_chips'); @@ -2431,17 +2568,144 @@ $historyFields = [ }); } - // ─── Inline Autotext Dropdowns (Frequency, Severity, Duration) ───────── + // ─── Inline Autotext Dropdowns (Complaint Name, Frequency, Severity, Duration) ───────── var _DISCHARGE_FREQ_OPTIONS = ['daily', 'twice daily', 'weekly', 'intermittent', 'continuous', 'occasional']; var _DISCHARGE_SEV_OPTIONS = ['mild', 'moderate', 'severe', 'profound']; var _DISCHARGE_DUR_UNITS = ['hours', 'days', 'weeks', 'months', 'years']; + var _dischargeRowDdIdx = -1; function _positionDischargeDd($dd, $input) { if (!$input || !$input.length) return; var r = $input[0].getBoundingClientRect(); - $dd.css({ top: (r.bottom + 2) + 'px', left: r.left + 'px', width: Math.max(r.width, 160) + 'px' }); + $dd.css({ top: (r.bottom + 2) + 'px', left: r.left + 'px', width: Math.max(r.width, 180) + 'px' }); } + function renderRowComplaintDropdown(rows, $inp, idx) { + var $dd = $('#discharge_row_complaint_dd').empty(); + _dischargeRowDdIdx = -1; + if (!rows || !rows.length) { + $dd.append('
No matching complaints found
'); + _positionDischargeDd($dd, $inp); + $dd.show(); + return; + } + + rows.forEach(function(row) { + var term = ((row.name || row.term) || '').toString(); + var source = (row.source || '').toString(); + var hierarchy = (row.hierarchy || '').toString(); + var isSnomed = source === 'snomed'; + var nameColor = isSnomed ? '#0d6efd' : '#212529'; + + var $item = $('
'); + $item.append($('
').text(term)); + if (isSnomed && hierarchy) { + $item.append($('
').text(hierarchy)); + } + $item.data('term', term); + + $item.on('mouseenter', function() { $(this).css('background', '#f0f4ff'); }) + .on('mouseleave', function() { $(this).css('background', ''); }) + .on('mousedown', function(e) { e.preventDefault(); }) + .on('click', function() { + var selectedTerm = $(this).data('term') || term; + $inp.val(selectedTerm); + if (idx >= 0 && idx < selectedDischargeComplaints.length) { + selectedDischargeComplaints[idx].term = selectedTerm; + syncDischargeComplaintJsonField(); + } + $dd.hide().empty(); + _dischargeRowDdIdx = -1; + $inp.closest('tr').find('.complaint-freq-input').trigger('focus'); + }); + + $dd.append($item); + }); + + _positionDischargeDd($dd, $inp); + $dd.show(); + } + + $(document).on('input focus', '.complaint-name-input', function(e) { + var $inp = $(this); + var q = ($inp.val() || '').trim(); + var idx = parseInt($inp.attr('data-idx'), 10); + + if (idx >= 0 && idx < selectedDischargeComplaints.length) { + selectedDischargeComplaints[idx].term = $inp.val(); + syncDischargeComplaintJsonField(); + } + + if (q.length < 1) { + $('#discharge_row_complaint_dd').hide().empty(); + _dischargeRowDdIdx = -1; + return; + } + + var cacheKey = q.toUpperCase(); + if (_dischargeComplaintSearchCache[cacheKey]) { + renderRowComplaintDropdown(_dischargeComplaintSearchCache[cacheKey], $inp, idx); + return; + } + + if (_dischargeComplaintSearchTimer) clearTimeout(_dischargeComplaintSearchTimer); + if (_dischargeComplaintXhr) { + try { _dischargeComplaintXhr.abort(); } catch(e){} + _dischargeComplaintXhr = null; + } + + _dischargeComplaintSearchTimer = setTimeout(function() { + if (document.activeElement !== $inp[0]) return; + _dischargeComplaintXhr = $.ajax({ + url: '', + data: { q: q }, + dataType: 'json', + success: function(data) { + _dischargeComplaintXhr = null; + if (document.activeElement !== $inp[0]) return; + var rows = (data && data.rows) ? data.rows : []; + _dischargeComplaintSearchCache[cacheKey] = rows; + renderRowComplaintDropdown(rows, $inp, idx); + }, + error: function() { + _dischargeComplaintXhr = null; + } + }); + }, 200); + }); + + $(document).on('keydown', '.complaint-name-input', function(e) { + var $dd = $('#discharge_row_complaint_dd'); + var $items = $dd.find('.discharge-row-complaint-item'); + if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { + if (!$dd.is(':visible') || !$items.length) return; + e.preventDefault(); + _dischargeRowDdIdx = e.key === 'ArrowDown' + ? Math.min(_dischargeRowDdIdx + 1, $items.length - 1) + : Math.max(_dischargeRowDdIdx - 1, 0); + $items.css('background', '').eq(_dischargeRowDdIdx).css('background', '#f0f4ff'); + } else if (e.key === 'Enter') { + if ($dd.is(':visible') && _dischargeRowDdIdx >= 0 && _dischargeRowDdIdx < $items.length) { + e.preventDefault(); + $items.eq(_dischargeRowDdIdx).trigger('click'); + } else { + $(this).closest('tr').find('.complaint-freq-input').trigger('focus'); + } + $dd.hide(); + _dischargeRowDdIdx = -1; + } else if (e.key === 'Escape') { + $dd.hide(); + _dischargeRowDdIdx = -1; + } + }); + + $(document).on('blur', '.complaint-name-input', function() { + setTimeout(function() { + $('#discharge_row_complaint_dd').hide(); + _dischargeRowDdIdx = -1; + }, 200); + }); + function getDischargeDurationSuggestions(input) { input = (input || '').toString().trim(); var numMatch = input.match(/^(\d+\.?\d*)\s*(.*)/); @@ -2542,6 +2806,9 @@ $historyFields = [ if (!$(e.target).closest('#discharge_complaint_lookup, #discharge_complaint_dropdown').length) { closeDischargeComplaintDropdown(); } + if (!$(e.target).closest('.complaint-name-input, #discharge_row_complaint_dd').length) { + $('#discharge_row_complaint_dd').hide(); + } if (!$(e.target).closest('.complaint-freq-input, #discharge_freq_dd').length) { $('#discharge_freq_dd').hide(); } @@ -7750,7 +8017,7 @@ $historyFields = [ var actionValue = submitter && submitter.name === 'action' ? String(submitter.value || '') : ''; var saveMode = submitter && submitter.dataset ? String(submitter.dataset.saveMode || '').toLowerCase() : ''; var statusTargetId = submitter && submitter.dataset ? String(submitter.dataset.statusId || '').trim() : ''; - var isComplaintAction = actionValue === 'add_complaint' || actionValue === 'remove_complaint'; + var isComplaintAction = actionValue === 'add_complaint' || actionValue === 'remove_complaint' || actionValue === 'update_complaint'; var isMedicineAction = actionValue === 'add_drug' || actionValue === 'remove_drug' || actionValue === 'apply_rx_group'; var targetSectionId = ''; @@ -7776,6 +8043,9 @@ $historyFields = [ if (isMedicineAction) { targetSectionId = 'section-medicine'; } + if (isComplaintAction) { + targetSectionId = 'section-complaints'; + } if (actionValue === 'add_procedure') { var procedureDateInput = form.querySelector('[name="new_procedure_date"]'); @@ -7797,7 +8067,7 @@ $historyFields = [ }).done(function(result) { // The server always returns JSON for AJAX requests (isAJAX() === true in CI4). // Because dataType is 'html', jQuery does NOT auto-parse it — result is a raw - // JSON string. Detect this by attempting JSON.parse and handle medicine actions. + // JSON string. Detect this by attempting JSON.parse and handle medicine/complaint actions. var parsedJson = null; if (typeof result === 'string' && result.charAt(0) === '{') { try { parsedJson = JSON.parse(result); } catch (e) { parsedJson = null; } @@ -7819,11 +8089,21 @@ $historyFields = [ noticeLevel = noticeLevel === 'success' ? 'error' : noticeLevel; } if (noticeText !== '') { - setSectionStatus('discharge_medicine_status', noticeText, noticeLevel === 'success' ? 'success' : 'error'); + var statusIdToUse = statusTargetId !== '' ? statusTargetId : ((targetSectionId === 'section-complaints' || isComplaintAction) ? 'discharge_complaint_status' : 'discharge_medicine_status'); + setSectionStatus(statusIdToUse, noticeText, noticeLevel === 'success' ? 'success' : 'error'); if (typeof window.notify === 'function') { window.notify(noticeLevel === 'success' ? 'success' : 'error', 'Discharge Update', noticeText); } } + // Re-render complaint table rows from returned complaintRows array + if ((isComplaintAction || targetSectionId === 'section-complaints') && Array.isArray(parsedJson.complaintRows)) { + if (typeof selectedDischargeComplaints !== 'undefined') { + selectedDischargeComplaints = parsedJson.complaintRows; + if (typeof renderDischargeComplaintTable === 'function') { + renderDischargeComplaintTable(); + } + } + } // Re-render medicine table rows from the returned drugRows array if (isMedicineAction && Array.isArray(parsedJson.drugRows)) { var tbody = document.getElementById('discharge_medicine_tbody');