You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

543 lines
22 KiB

{% extends "portal/base.html.twig" %}
{% block head %}
{{ parent() }}
<link href="../portal/sign/css/signer_modal.css?v={{ assetVersion | attr }}" rel="stylesheet" />
<script src="../interface/main/tabs/js/dialog_utils.js?v={{ assetVersion | attr }}"></script>
<script src="../portal/sign/assets/signature_pad.umd.js?v={{ assetVersion | attr }}"></script>
<script src="../portal/sign/assets/signer_api.js?v={{ assetVersion | attr }}"></script>
{% if payment_gateway == 'Stripe' %}
<script src="https://js.stripe.com/v3/"></script>
{% endif %}
{% if payment_gateway == 'AuthorizeNet' %}
{% if gateway_mode_production %}
<script src="https://js.authorize.net/v1/Accept.js"></script>
{% else %}
<script src="https://jstest.authorize.net/v1/Accept.js"></script>
{% endif %}
{% endif %}
<script>
var cpid = {{ patientID | js_escape }},
cuser = {{ user | js_escape }},
webRoot = {{ web_root | js_escape }},
ptName = {{ patientName | js_escape }},
whereto = {{ whereto | js_escape }},
siteId = {{ site_id | js_escape }},
inactivityTimeOut = {{ portal_timeout | js_escape }},
languageDefinitions = {{ language_defs | js_escape }},
webroot_url = webRoot,
tab_mode = true,
isPortal = 1;
function restoreSession() {
return true;
}
i18next.init({
lng: 'selected',
debug: false,
nsSeparator: false,
keySeparator: false,
resources: {
selected: {
translation: languageDefinitions
}
}
}).catch(error => {
console.log(error.message);
});
function persist(where, portalInit = false) {
if (where[0] !== '#') {
return;
}
whereto = where;
fetch('lib/persist.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(
{
'csrf_token_form': {{ csrfUtils | js_escape }},
'where': where,
'portal_init': portalInit
}
),
});
}
const activityMonitor = function () {
let timeOut, warnTimeOut, time;
if (Number(inactivityTimeOut) < 300) {
inactivityTimeOut = 900; // 15 minutes. < 5 minutes is too short.
}
time = inactivityTimeOut * 1000;
window.onload = resetLogOutTimer;
window.onmousemove = resetLogOutTimer;
window.onmousedown = resetLogOutTimer;
window.ontouchstart = resetLogOutTimer;
window.ontouchmove = resetLogOutTimer;
window.onclick = resetLogOutTimer;
window.onkeydown = resetLogOutTimer;
window.addEventListener('scroll', resetLogOutTimer, true);
function logoutWarn() {
const warnMsg = xl('Your current log on session will expire in 30 seconds.') +
'<br />' + xl('Please take action to prevent being logged out!');
syncAlertMsg(warnMsg, 28000); // from utility.js
}
function logout() {
let logoutUrl = "./index.php?site=" + encodeURIComponent(siteId);
location.replace(logoutUrl);
}
function resetWarnTimer() {
clearTimeout(warnTimeOut);
warnTimeOut = setTimeout(logoutWarn, time - 30000);
}
function resetLogOutTimer() {
$('#alert_box').remove(); // reset alert if set
resetWarnTimer();
clearTimeout(timeOut);
timeOut = setTimeout(logout, time);
}
};
$(function () {
$('#topNav [data-parent="#cardgroup"]').on('click', (e) => {
persist($(e.target).attr('href'), false);
});
if ($('body').css('direction') === "rtl") {
$('.float-left').each(function () {
$(this).addClass('float-right').removeClass('float-left');
});
$('.dropdown-menu-right').each(function () {
$(this).removeClass('dropdown-menu-right');
});
$('.dropdown-menu-md-right').each(function () {
$(this).removeClass('dropdown-menu-md-right');
});
}
$("#profilereport").load("get_profile.php", {}, function () {
$("table").addClass("table table-sm");
$(".demographics td").removeClass("label");
$(".demographics td").addClass("bold");
$(".insurance table").addClass("table-sm table-striped");
$("#editDems").click(function () {
showProfileModal()
});
});
$("#medicationlist").load("./get_medications.php", {}, function () {
});
$("#labresults").load("./get_lab_results.php", {}, function () {
});
$("#amendmentslist").load("./get_amendments.php", {}, function () {
});
$("#problemslist").load("./get_problems.php", {}, function () {
});
$("#allergylist").load("./get_allergies.php", {}, function () {
});
$("#reports").load("./report/portal_patient_report.php?pid=" + {{ patientID | js_url }}, {}, function () {
});
{% if portal_two_payments %}
$("#payment").load("./portal_payment.php", {}, function () {
});
{% endif %}
{% if isEasyPro %}
$("#pro").load("./get_pro.php", {}, function () {
});
{% endif %}
$(".generateDoc_download").click(function () {
$("#doc_form").submit();
});
function showProfileModal() {
var title = {{ 'Profile Edits Red = Charted Values and Blue = Patient Edits' | xlj }};
var params = {
buttons: [{
text: {{ 'Help' | xlj }},
close: false,
style: 'info',
id: 'formHelp'
},
{
text: {{ 'Cancel' | xlj }},
close: true,
style: 'default'
},
{
text: {{ 'Revert Edits' | xlj }},
close: false,
style: 'danger',
id: 'replaceAllButton'
},
{
text: {{ 'Submit Changes' | xlj }},
close: false,
style: 'success',
id: 'donePatientButton'
}],
sizeHeight: 'full',
allowDrag: false,
onClosed: 'reload',
resolvePromiseOn: 'init',
type: 'GET',
url: webRoot + '/portal/patient/patientdata?pid=' + encodeURIComponent(cpid) + '&user=' + encodeURIComponent(cuser)
};
dlgopen('', '', 'modal-xl', 500, '', title, params).then(function (dialog) {
$('div.modal-body', dialog).addClass('overflow-auto');
});
}
function saveProfile() {
page.updateModel();
}
let gowhere = {{ whereto | js_escape }};
$(gowhere).collapse('show');
$('#cardgroup').on('hide.bs.collapse', '.show', function (e) {
let target = this.attributes.id.nodeValue;
if (whereto.includes(target)) {
whereto = '';
return false;
}
});
$('#popwait').addClass('d-none');
$('#callccda').click(function () {
$('#popwait').removeClass('d-none');
});
// start watch for inactivity
activityMonitor();
});
function editAppointment(mode, deid) {
let mdata = {};
let title = '';
if (mode === 'add') {
title = {{ 'Request New Appointment' | xlj }};
mdata = {
pid: deid
};
} else if (mode === 'recurring') {
let msg = {{ 'A Recurring Appointment. Please contact your appointment desk for any changes.' | xlj }};
signerAlertMsg(msg, 8000);
return false;
} else {
title = {{ 'Edit Appointment' | xlj }};
mdata = {
eid: deid
};
}
var params = {
dialogId: 'editpop',
buttons: [{text: 'Cancel', close: true, style: 'btn-sm btn-secondary'}],
allowDrag: false,
size: 800,
title: title,
type: "GET",
url: './add_edit_event_user.php',
data: mdata
};
/*
* A couple notes on dialog.ajax .alert etc.
* opener is not required. library will handle for you.
* these run in the same scope as calling script.
* so same styles, dependencies are in scope.
* a promise is returned for doing other neat stuff.
*
* */
dialog.ajax(params);
}
function changeCredentials(e) {
title = {{ 'Please Enter New Credentials' | xlj }};
dlgopen("./account/index_reset.php", '', 575, 600, null, title, {});
}
{% if isEasyPro %}
function writeResult(score, stdErr, assessmentOID) {
$.ajax({
url: '../library/ajax/easipro_util.php',
data: {
'csrf_token_form': {{ csrfUtils | js_escape }},
'function': 'record_result',
'score': score,
'stdErr': stdErr,
'assessmentOID': assessmentOID
},
type: 'POST',
dataType: 'script'
});
}
function selectResponse(obj, assessmentOID) {
$.ajax({
url: '../library/ajax/easipro_util.php',
type: "POST",
data: {
'csrf_token_form': {{ csrfUtils | js_escape }},
'function': 'select_response',
'assessmentOID': assessmentOID,
'ItemResponseOID': obj.name,
'Response': +obj.id
},
dataType: "json",
success: function (data) {
if (data.DateFinished != '') {
document.getElementById("Content").innerHTML = jsText({{ 'You have finished the assessment.' | xlj }}) + "<br /> " + jsText({{ 'Thank you' | xlj }});
$('.assessment-row').toggleClass('d-none');
document.getElementById("asst_" + assessmentOID).innerHTML = "<i class='fa fa-check-circle'></i>";
document.getElementById("asst_status_" + assessmentOID).innerHTML = "completed";
$.ajax({
url: '../library/ajax/easipro_util.php',
type: "POST",
data: {
'csrf_token_form': {{ csrfUtils | js_escape }},
'function': 'collect_results',
'assessmentOID': assessmentOID
},
dataType: "json",
success: function (data) {
writeResult(data.Items[0].Theta, data.Items[0].StdError, assessmentOID);
}
});
return
}
var screen = "";
for (var j = 0; j < data.Items[0].Elements.length; j++) {
if (typeof (data.Items[0].Elements[j].Map) == 'undefined') {
screen = screen + `<label class="font-weight-bolder mx-1">${data.Items[0].Elements[j].Description}</label>`
} else {
for (var k = 0; k < data.Items[0].Elements[j].Map.length; k++) {
screen = screen + `<div class="form-row"><input type="button" class='form-control' id="${data.Items[0].Elements[j].Map[k].Value}" name="${data.Items[0].Elements[j].Map[k].ItemResponseOID}" value="${data.Items[0].Elements[j].Map[k].Description}" onclick="selectResponse(this,'${assessmentOID}')" /></div>`;
}
}
}
document.getElementById("Content").innerHTML = screen;
},
error: function (jqXHR, textStatus, errorThrown) {
alert("An error occurred");
}
});
}
function startAssessment(param, assessmentOID) {
param.innerHTML = "<i class='fa fa-circle-notch fa-spin'></i> " + jsText({{ 'Loading' | xlj }});
$.ajax({
url: '../library/ajax/easipro_util.php',
type: "POST",
data: {
'csrf_token_form': {{ csrfUtils | js_escape }},
'function': 'start_assessment',
'assessmentOID': assessmentOID
},
dataType: "json",
success: function (data) {
var screen = "";
let title = $("#" + "hide_assessment_" + assessmentOID).closest('tr').children('td:first').text();
document.getElementById("ContentTitle").innerHTML = "<h5>" + jsText(title) + "</h5>";
$('.assessment-row').toggleClass('d-none');
for (var j = 0; j < data.Items[0].Elements.length; j++) {
if (typeof (data.Items[0].Elements[j].Map) == 'undefined') {
screen = screen + `<label class="font-weight-bolder mx-1">${data.Items[0].Elements[j].Description}</label>`;
} else {
for (var k = 0; k < data.Items[0].Elements[j].Map.length; k++) {
screen = screen + `<div class="form-row"><input type="button" class='form-control' id="${data.Items[0].Elements[j].Map[k].Value}" name="${data.Items[0].Elements[j].Map[k].ItemResponseOID}" value="${data.Items[0].Elements[j].Map[k].Description}" onclick="selectResponse(this, '${assessmentOID}')" /></div>`;
}
}
}
document.getElementById("Content").innerHTML = screen;
param.innerHTML = jsText({{ 'Assessment Started' | xlj }});
},
error: function (jqXHR, textStatus, errorThrown) {
param.innerHTML = jsText({{ 'Start Assessment' | xlj }});
alert("An error occurred");
}
});
}
{% endif %}
</script>
{{ fireEvent(eventNames.scriptsRenderPre) }}
{% endblock %}
{% block pagetitle %}
{{ pagetitle | text }}
{% endblock %}
{% block header %}
{% include "portal/header.html.twig" %}
{% endblock %}
{% block content %}
<section class="flex-column accordion" id="cardgroup">
<div id="popwait" class="alert alert-warning d-none">
<strong>{{ 'Working!' | xlt }}</strong>
{{ 'Please wait...' | xlt }}</div>
<div class="collapse overflow-auto" data-parent="#cardgroup" id="lists">
<div class="card">
<header class="card-header bg-primary text-light">{{ 'Medications' | xlt }}</header>
<div id="medicationlist" class="card-body bg-light"></div>
</div>
<div class="card">
<header class="card-header bg-primary text-light">{{ 'Medications Allergy List' | xlt }}</header>
<div id="allergylist" class="card-body bg-light"></div>
</div>
<div class="card">
<header class="card-header bg-primary text-light">{{ 'Issues List' | xlt }}</header>
<div id="problemslist" class="card-body bg-light"></div>
</div>
<div class="card">
<header class="card-header bg-primary text-light">{{ 'Amendment List' | xlt }}</header>
<div id="amendmentslist" class="card-body bg-light"></div>
</div>
<div class="card">
<header class="card-header bg-primary text-light">{{ 'Lab Results' | xlt }}</header>
<div id="labresults" class="card-body bg-light"></div>
</div>
</div>
<div class="card collapse overflow-auto" data-parent="#cardgroup" id="reportcard">
<header class="card-header bg-primary text-light">{{ 'Reports' | xlt }}</header>
<div id="reports" class="card-body"></div>
</div>
<div class="card collapse" data-parent="#cardgroup" id="profilecard">
<div id="profilereport" class="card-body bg-light"></div>
</div>
<div class="collapse" data-parent="#cardgroup" id="documentscard">
<div class="card">
<div id="patdocuments" class="card-body">
<iframe src="{{ web_root | attr }}/portal/patient/onsitedocuments?pid={{ patientID | attr_url }}" class="w-100 vh-100 border-0"></iframe>
</div>
</div>
</div>
<div class="collapse" data-parent="#cardgroup" id="secure-msgs-card">
<div class="card">
<div id="secure-msgs" class="card-body">
<iframe src="{{ web_root | attr }}/portal/messaging/messages.php" class="w-100 vh-100 border-0"></iframe>
</div>
</div>
</div>
{% if allow_portal_appointments %}
<div class="collapse mt-2 overflow-auto" data-parent="#cardgroup" id="appointmentcard">
<div class="container-fluid">
<h3 class="text-center">{{ 'Appointments' | xlt }}</h3>
<div class="row">
{% if appointments|length > 0 %}
{% for appt in appointments %}
{% include 'portal/appointment-item.html.twig' with {appt: appt} %}
{% endfor %}
{% if appointmentLimit == appointmentCount %}
<p>{{ 'Display limit reached' | xlt }}
<br>
{{ 'More appointments may exist' | xlt }}</p>
{% endif %}
{% else %}
<h3 class='text-center'>{{ 'No Appointments' | xlt }}</h3>
{% endif %}
</div>
<div class="mb-3">
<a class='btn btn-primary btn-block' href='#' onclick="editAppointment('add',{{ patientID | attr_js }})">{{ 'Schedule A New Appointment' | xlt }}</a>
</div>
</div>
</div>
<!-- /.row -->
{% endif %}
{% if portal_two_payments %}
<div class="collapse overflow-auto" data-parent="#cardgroup" id="paymentcard">
<div class="card">
<header class="card-header bg-primary text-light">{{ 'Payments' | xlt }}</header>
<div id="payment" class="card-body bg-light"></div>
</div>
</div>
{% endif %}
{% if allow_portal_chat %}
<div class="collapse overflow-auto" data-parent="#cardgroup" id="messagescard">
<div class="card pt-0 pb-0">
<header class="card-header bg-primary text-light">{{ 'Secure Chat' | xlt }}</header>
<div id="chat" class="card-body p-0 overflow-auto">
<iframe src="./messaging/secure_chat.php" class="w-100" style="height: calc(100vh - 120px);"></iframe>
</div>
</div>
</div>
{% endif %}
{% if portal_onsite_document_download %}
<div class="card collapse overflow-auto" data-parent="#cardgroup" id="downloadcard">
<header class="card-header bg-primary text-light">{{ 'Download Documents' | xlt }}</header>
<div id="docsdownload" class="card-body">
<div>
<span class="text">{{ 'Download all patient documents' | xlt }}</span>
<form name='doc_form' id='doc_form' action='./get_patient_documents.php' method='post'>
<input type="button" class="generateDoc_download" value="{{ 'Download' | xla }}" />
</form>
</div>
</div>
<!-- /.card-body -->
</div>
{% endif %}
{% if portal_two_ledger %}
<div class="collapse overflow-auto" data-parent="#cardgroup" id="ledgercard">
<div class="card">
<header class="card-header bg-primary text-light">{{ 'Ledger' | xlt }}</header>
<div id="patledger" class="card-body">
<iframe src="./report/pat_ledger.php" class="w-100 vh-100 border-0"></iframe>
</div>
</div>
</div>
{% endif %}
{% if isEasyPro %}
<div class="card collapse overflow-auto" data-parent="#cardgroup" id="procard">
<header class="card-header bg-primary text-light">{{ 'Patient Reported Outcomes' | xlt }}</header>
<div id="pro" class="card-body bg-light"></div>
</div>
{% endif %}
{{ fireEvent(eventNames.sectionRenderPost) }}
</section>
{% endblock %}