fix: firefox close dialog from smart dsi edit source (#7789)
[openemr.git] / portal / import_template_ui.php
blob6e0282f5e5b8945c3315324f937ca4458b1bd499
1 <?php
3 /**
4 * import_template_ui.php
6 * @package OpenEMR
7 * @link https://www.open-emr.org
8 * @author Jerry Padgett <sjpadgett@gmail.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @copyright Copyright (c) 2016-2022 Jerry Padgett <sjpadgett@gmail.com>
11 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
12 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
15 require_once("../interface/globals.php");
17 use OpenEMR\Common\Acl\AclMain;
18 use OpenEMR\Common\Csrf\CsrfUtils;
19 use OpenEMR\Core\Header;
20 use OpenEMR\Events\Messaging\SendNotificationEvent;
21 use OpenEMR\Services\DocumentTemplates\DocumentTemplateService;
22 use OpenEMR\Services\PatientPortalService;
23 use OpenEMR\Services\QuestionnaireService;
25 if (!(isset($GLOBALS['portal_onsite_two_enable'])) || !($GLOBALS['portal_onsite_two_enable'])) {
26 echo xlt('Patient Portal is turned off');
27 exit;
30 // Service
31 $eventDispatcher = $GLOBALS['kernel']->getEventDispatcher();
32 $portalService = new PatientPortalService();
33 // auto allow if a portal user else must be an admin
34 $authUploadTemplates = $portalService::authPortalUser('admin', 'forms');
36 $templateService = new DocumentTemplateService();
37 $from_demo_pid = $_GET['from_demo_pid'] ?? '0';
38 $patient = $_REQUEST['selected_patients'] ?? null;
39 $patient = $patient ?: ($_REQUEST['upload_pid'] ?? 0);
40 // our lists
41 $category = $_REQUEST['template_category'] ?? '';
42 $category_list = $templateService->fetchDefaultCategories();
43 $profile_list = $templateService->fetchDefaultProfiles();
44 $group_list = $templateService->fetchDefaultGroups();
45 // for empty lists
46 $none_message = xlt("Nothing to show for current actions.");
47 // init status array
48 $audit_status_blank = array(
49 'audit_id' => null,
50 'pid' => null,
51 'create_date' => null,
52 'doc_type' => null,
53 'id' => null,
54 'facility' => null,
55 'provider' => null,
56 'encounter' => null,
57 'patient_signed_status' => null,
58 'patient_signed_time' => null,
59 'authorize_signed_time' => null,
60 'accept_signed_status' => null,
61 'authorizing_signator' => null,
62 'review_date' => null,
63 'denial_reason' => null,
64 'authorized_signature' => null,
65 'patient_signature' => null,
66 'full_document' => null,
67 'file_name' => null,
68 'file_path' => null,
69 'template_data' => null,
70 'date' => null,
71 'patient_id' => null,
72 'activity' => null,
73 'require_audit' => null,
74 'pending_action' => null,
75 'action_taken' => null,
76 'status' => null,
77 'narrative' => null,
78 'table_action' => null,
79 'table_args' => null,
80 'action_user' => null,
81 'action_taken_time' => null,
82 'checksum' => null,
85 $searchTerm = '';
86 if (!empty($_GET['search_term']) || !empty($_GET['search'])) {
87 $searchTerm = $_GET['search_term'] ?? $_GET['search'];
90 <!DOCTYPE html>
91 <head>
92 <meta charset="UTF-8">
93 <title><?php echo xlt('Portal'); ?> | <?php echo xlt('Templates'); ?></title>
94 <meta name="description" content="Developed By sjpadgett@gmail.com">
95 <?php Header::setupHeader(['datetime-picker', 'select2', 'summernote']); ?>
96 <script>
97 const profiles = <?php echo js_escape($profile_list); ?>;
98 let currentEdit = "";
99 let editor;
100 let callBackCmd = null;
102 <?php
103 $eventDispatcher->dispatch(new SendNotificationEvent($pid ?? 0, ['is_onetime' => 1]), SendNotificationEvent::JAVASCRIPT_READY_NOTIFICATION_POST);
105 $(document).ready(function () {
106 let selectDropdown = $('.select-dropdown');
107 selectDropdown.select2({
108 multiple: true,
109 placeholder: 'Type to search.',
110 theme: 'bootstrap4',
111 dropdownAutoWidth: true,
112 width: '100%',
113 closeOnSelect: false
116 let searchBox = document.querySelector('.select2-search__field');
118 searchBox.addEventListener('keydown', function (event) {
119 if (event.key === 'Enter') {
120 event.preventDefault();
121 $('#selectSearch').trigger('click');
124 searchBox.addEventListener('input', function (event) {
125 let currentValue = event.target.value;
126 $('#search_term').val(currentValue);
129 // Set the search term in the search box after the page reloads
130 let searchTerm = <?php echo js_escape($searchTerm); ?>;
131 if (searchTerm) {
132 let searchBox = document.querySelector('.select2-search__field');
133 $(searchBox).val(searchTerm).trigger('input');
136 document.querySelector('.select2-search__field').focus();
137 // When the search box is opened update the hidden input
138 selectDropdown.on('select2:open', function () {
139 let searchBox = document.querySelector('.select2-search__field');
140 $(searchBox).val($('#search_term').val()).trigger('input');
141 $(searchBox).on('input', function () {
142 let searchTerm = $(this).val();
143 $('#search_term').val(searchTerm);
146 // Get selected templates before the form is submitted
147 $('#edit_form').on('submit', function (e) {
148 e.preventDefault();
149 let checked = getSendChecks();
150 if (checked.length > 0) {
151 return false;
153 this.submit();
156 $("#selectSearch").on('click', function () {
157 $('#edit_form').submit();
160 document.getElementById('clearSelection').addEventListener('click', function () {
161 let selectedPatients = $('#selected_patients');
162 selectedPatients.val(null).trigger('change');
163 let searchBox = document.querySelector('.select2-search__field');
164 $(searchBox).val(null).trigger('input');
165 $('#search_term').val("");
166 $('#edit_form').submit();
169 $('#selected_patients').on('change', function () {
170 let selectedValues = [];
171 $(this).find('option:selected').each(function () {
172 selectedValues.push({
173 pid: $(this).val(),
174 ptname: $(this).text()
177 $('#persist_checks').val(JSON.stringify(selectedValues));
180 $('#selected_patients').trigger('change');
183 $(function () {
184 let ourSelect = $('.select-questionnaire');
185 /* Questionnaires */
186 ourSelect.select2({
187 multiple: false,
188 placeholder: xl('Type to search Questionnaire Repository.'),
189 theme: 'bootstrap4',
190 dropdownAutoWidth: true,
191 width: 'resolve',
192 closeOnSelect: true,
193 <?php require($GLOBALS['srcdir'] . '/js/xl/select2.js.php'); ?>
195 $(document).on('select2:open', () => {
196 document.querySelector('.select2-search__field').focus();
198 ourSelect.on("change", function (e) {
199 let data = $('#select_item').select2('data');
200 if (data) {
201 document.getElementById('upload_name').value = data[0].text;
203 $('#repository-submit').removeClass('d-none');
206 $("#repository-submit").on("click", function (e) {
207 top.restoreSession();
208 let data = $('#select_item').select2('data');
209 if (data) {
210 document.getElementById('upload_name').value = data[0].text;
211 } else {
212 alert(xl("Missing Template name."))
213 return false;
215 return true;
218 $('#fetch_files').on('click touchstart', function () {
219 $(this).val('');
222 $('#fetch_files').change(function (e) {
223 const file = document.getElementById("fetch_files").files.item(0);
224 const fileName = file.name;
225 let howManyFiles = document.getElementById("fetch_files").files.length;
226 $('#upload_submit').removeClass('d-none');
227 if (howManyFiles === 1 && document.getElementById("upload_scope").checked) {
228 if (fileName.toLowerCase().indexOf('.json') > 0 || file.type === 'application/json') {
229 $('#upload_submit_questionnaire').removeClass('d-none');
230 resolveImport();
232 } else {
233 if (fileName.toLowerCase().indexOf('.json') > 0 || file.type === 'application/json') {
234 document.getElementById("upload_submit_questionnaire").type = 'submit';
235 document.getElementById("upload_submit_questionnaire").removeAttribute("onclick");
236 document.getElementById("upload_submit_questionnaire").innerText = xl("Questionnaires Repository All")
237 $('#upload_submit_questionnaire').removeClass('d-none');
240 return false;
243 $('input:checkbox[name=send]').change(function () {
244 let checked = getSendChecks();
245 if (checked.length > 0) {
246 $('#send-button').removeClass('d-none');
247 $('#category_group').addClass('d-none');
248 $('#send-profile-hide').addClass('d-none');
249 } else {
250 $('#send-button').addClass('d-none');
251 $('#category_group').removeClass('d-none');
255 $('input:checkbox[name=send_profile]').change(function () {
256 $('#send-profile-hide').removeClass('d-none');
257 $('#category_group').addClass('d-none');
258 $('input:checkbox[name=send]').addClass('d-none');
261 $('#upload-nav').on('hidden.bs.collapse', function () {
262 $('#upload-nav-value').val('collapse');
264 $('#upload-nav').on('show.bs.collapse', function () {
265 $('#upload-nav-value').val('show');
266 //$('#edit_form').submit();
269 $("#template_category").change(function () {
270 $('#edit_form').submit();
273 $('#template-collapse').on('show.bs.collapse', function () {
274 $('#edit_form #all_state').val('show');
276 $('#template-collapse').on('hidden.bs.collapse', function () {
277 $('#edit_form #all_state').val('collapse');
280 $('#assigned_collapse').on('show.bs.collapse', function () {
281 $('#repository-collapse').collapse('hide');
282 $('#template-collapse').collapse('hide');
283 $('#edit_form #assigned_state').val('show');
285 $('#assigned_collapse').on('hidden.bs.collapse', function () {
286 $('#edit_form #assigned_state').val('collapse');
289 $('#repository-collapse').on('show.bs.collapse', function () {
290 $('#edit_form #repository_send_state').val('show');
292 $('#repository-collapse').on('hidden.bs.collapse', function () {
293 $('#edit_form #repository_send_state').val('collapse');
296 let selText = '';
297 let selCat = $('#template_category').find(':selected').text();
298 let ids = $('#selected_patients').find(':selected').each(function () {
299 selText += $(this).text() + '; ';
301 $('#upload_scope_category').empty().append(' ' + xl('For Category') + ': ' + selCat);
304 // a callback from dlgclose(fn) in render form
305 function doImportSubmit() {
306 // todo add message to user
307 top.restoreSession();
308 document.getElementById('form_upload').submit();
309 return false;
312 function resolveImport(mode = 'render_import') {
313 if (mode === 'render_import') {
314 const file = document.getElementById("fetch_files").files.item(0);
315 if (file.name.toLowerCase().indexOf('.json') === -1 && file.type !== 'application/json') {
316 return false;
319 top.restoreSession();
320 let callBack = '';
321 let url = './questionnaire_render.php?mode=' + encodeURIComponent(mode);
322 dlgopen(url, 'pop-questionnaire', 'modal-lg', 850, '', '', {
323 allowDrag: true,
324 allowResize: true,
325 sizeHeight: 'full',
326 resolvePromiseOn: 'close',
327 }).then(() => {
328 // set callBackCmd from iframe then eval here
329 // currently using callback from dlgclose();
330 return false;
334 let questionnaireViewCurrent = function (encounter, flag = '') {
335 currentEdit = encounter;
336 alertMsg(xl("New coming feature. View patient progress with the completion of the form with the ability to send a secure notification to patient."), 6000, 'success')
337 return false;
340 let templateEdit = function (id, flag = '') {
341 currentEdit = id;
342 handleTemplate(id, 'get', '', flag);
343 return false;
346 let templateSave = function () {
347 let markup = CKEDITOR.instances.templateContent.getData();
348 handleTemplate(currentEdit, 'save', markup);
351 let templateDelete = function (id, template = '') {
352 let delok = confirm(<?php echo xlj('You are about to delete a template'); ?> +
353 ": " + "\n" + <?php echo xlj('Is this Okay?'); ?>);
354 if (delok === true) {
355 handleTemplate(id, 'delete', '', false, template, <?php echo js_escape(CsrfUtils::collectCsrfToken('import-template-delete')); ?>)
357 return false;
360 function getSendChecks() {
361 let checked = [];
362 $('input:checked[name=send]:checked').each(function () {
363 let isProfile = this.dataset.send_profile;
364 if (isProfile == 'yes') {
365 checked.push([$(this).val(), true]);
366 } else {
367 checked.push($(this).val());
370 console.log(checked)
371 return checked;
374 function getSendCheckProfiles() {
375 let checked = [];
376 $('input:checked[name=send_profile]:checked').each(
377 function () {
378 let isProfile = this.dataset.send_profile;
379 if (isProfile == 'yes') {
380 checked.push($(this).val());
383 console.log(checked)
384 return checked;
387 function updateCategory(id) {
388 top.restoreSession();
389 let url = 'import_template.php';
390 let category = event.currentTarget.value;
391 const data = new FormData();
392 data.append('docid', id);
393 data.append('category', category);
394 data.append('mode', 'update_category');
395 fetch(url, {
396 method: 'POST',
397 body: data,
398 }).then(rtn => rtn.text()).then((rtn) => {
399 (async (time) => {
400 await asyncAlertMsg(rtn, time, 'success', 'lg');
401 })(2000).then(rtn => {
402 //document.edit_form.submit();
404 }).catch((error) => {
405 console.error('Error:', error);
409 function sendTemplate(mode = 'send', content = '') {
410 top.restoreSession();
411 let url = 'import_template.php';
412 let ids = $('#selected_patients').select2('val');
413 let category = $('#template_category').val();
414 let checked = getSendChecks();
415 const data = new FormData();
416 data.append('docid', JSON.stringify(ids));
417 data.append('category', category);
418 data.append('checked', JSON.stringify(checked));
419 data.append('mode', mode);
420 data.append('content', content);
421 fetch(url, {
422 method: 'POST',
423 body: data,
424 }).then(rtn => rtn.text()).then((rtn) => {
425 (async (time) => {
426 await asyncAlertMsg(rtn, time, 'success', 'lg');
427 })(1500).then(rtn => {
428 document.edit_form.submit();
430 }).catch((error) => {
431 console.error('Error:', error);
435 function sendProfiles() {
436 top.restoreSession();
437 let mode = 'send_profiles'
438 let url = 'import_template.php';
439 let checked = getSendCheckProfiles();
440 const data = new FormData();
441 data.append('checked', JSON.stringify(checked));
442 data.append('mode', mode);
443 fetch(url, {
444 method: 'POST',
445 body: data,
446 }).then(rtn => rtn.text()).then((rtn) => {
447 (async (time) => {
448 await asyncAlertMsg(rtn, time, 'success', 'lg');
449 })(1500).then(rtn => {
450 document.edit_form.submit();
452 }).catch((error) => {
453 console.error('Error:', error);
457 function handleTemplate(id, mode, content = '', isDocument = '', template = '', csrf = '') {
458 top.restoreSession();
459 let libUrl = 'import_template.php';
460 let renderUrl = 'import_template.php?mode=editor_render_html&docid=' + id;
462 if (document.getElementById('is_modal').checked && mode === 'get') {
463 dialog.popUp(renderUrl, null, 'edit' + id);
464 return false;
466 if (isDocument == true) {
467 dialog.popUp(renderUrl, null, ('edit' + id));
468 return false;
470 if (mode == 'get') {
471 renderUrl += '&dialog=true';
472 dlgopen(renderUrl, 'pop-editor', 'modal-lg', 850, '', '', {
473 resolvePromiseOn: 'show',
474 allowDrag: true,
475 allowResize: true,
476 sizeHeight: 'full'
479 $.ajax({
480 type: "POST",
481 url: libUrl,
482 data: {docid: id, mode: mode, content: content, template: template, csrf_token_form: csrf},
483 error: function (qXHR, textStatus, errorThrow) {
484 console.log("There was an error");
485 alert(<?php echo xlj("File Error") ?> +"\n" + id)
487 success: function (templateHtml, textStatus, jqXHR) {
488 document.edit_form.submit();
493 function popProfileDialog() {
494 top.restoreSession();
495 let url = './import_template.php?mode=render_profile';
496 dlgopen(url, 'pop-profile', 'modal-lg', 850, '', '', {
497 allowDrag: true,
498 allowResize: true,
499 sizeHeight: 'full',
503 function popPatientDialog() {
504 top.restoreSession();
505 let url = './lib/patient_groups.php';
506 dlgopen(url, 'pop-profile', 'modal-lg', 850, '', '', {
507 allowDrag: true,
508 allowResize: true,
509 sizeHeight: 'full'
513 function popGroupsDialog() {
514 let url = './lib/patient_groups.php?render_group_assignments=true';
515 dlgopen(url, 'pop-groups', 'modal-lg', 850, '', '', {
516 allowDrag: true,
517 allowResize: true,
518 sizeHeight: 'full',
522 function createBlankTemplate() {
523 top.restoreSession();
524 let name = prompt(xl('Enter a valid name for this new template.') + "\n" + xl("For example: Pain Assessment"));
525 if (name === null) {
526 return false;
528 if (name === "") {
529 alert(xl('A name must be entered. Try again.'));
530 createBlankTemplate();
532 $("#upload_name").val(name);
533 return true;
535 </script>
536 <style>
537 .select2-container .select2-search--inline .select2-search__field {
538 min-width: 5vw !important;
539 color: var(--light);
540 background-color: var(--dark);
543 .select2-container {
544 max-width: 50% !important;
547 .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove {
548 color: #dc3545;
549 font-size: 1rem;
550 line-height: revert !important;
553 caption {
554 caption-side: top !important;
557 .note-editor.dragover .note-dropzone {
558 display: none
560 </style>
561 </head>
562 <body class="body-top">
563 <div class='container-xl'>
564 <nav class='nav navbar bg-light text-dark sticky-top'>
565 <span class='title'><?php echo xlt('Template Maintenance'); ?></span>
566 <div class="ml-auto">
567 <label class="form-check"><?php echo xlt('Full Editor'); ?>
568 <input type='checkbox' class='form-check-inline mx-1' id='is_modal' name='is_modal' checked='checked' />
569 </label>
570 </div>
571 <div class='btn-group ml-1'>
572 <button type='button' class='btn btn-secondary' data-toggle='collapse' data-target='#help-panel'>
573 <?php echo xlt('Help') ?>
574 </button>
575 <button class='btn btn-success' type='button' onclick="location.href='./patient/provider'">
576 <?php echo xlt('Dashboard'); ?>
577 </button>
578 </div>
579 </nav>
580 <div class='col col-12'>
581 <hr />
582 <?php include_once('./../Documentation/help_files/template_maintenance_help.php'); ?>
583 <!-- Actions Scope to act on -->
584 <nav class='navbar navbar-dark bg-dark text-light sticky-top'>
585 <form id="edit_form" name="edit_form" class="row form-inline w-100" action="" method="get">
586 <a class='navbar-brand ml-1'><?php echo xlt('Scope'); ?></a>
587 <?php
588 $select_cat_options = '<option value="">' . xlt('General') . "</option>\n";
589 foreach ($category_list as $option_category) {
590 if (stripos($option_category['option_id'], 'repository') !== false) {
591 continue;
593 if ($category === $option_category['option_id']) {
594 $select_cat_options .= "<option value='" . attr($option_category['option_id']) . "' selected>" . text($option_category['title']) . "</option>\n";
595 } else {
596 $select_cat_options .= "<option value='" . attr($option_category['option_id']) . "'>" . text($option_category['title']) . "</option>\n";
600 <div class="input-group" id="category_group">
601 <label class="font-weight-bold mx-1" for="template_category"><?php echo xlt('Category'); ?></label>
602 <select class="form-control" id="template_category" name="template_category">
603 <?php echo $select_cat_options ?>
604 </select>
605 </div>
606 <div class="form-group mx-2">
607 <div class='btn-group ml-1'>
608 <button type='submit' class='btn btn-save btn-primary'><?php echo xlt("Submit"); ?></i></button>
609 <button type='button' id="send-button" class='btn btn-transmit btn-success d-none' onclick="return sendTemplate()">
610 <?php echo xlt('Send'); ?>
611 </button>
612 <button type='button' class='btn btn-primary' onclick='return popProfileDialog()'><?php echo xlt('Profiles') ?></button>
613 <button type='button' class='btn btn-primary' onclick='return popPatientDialog()'><?php echo xlt('Groups') ?></button>
614 <button type='button' class='btn btn-primary' onclick='return popGroupsDialog()'><?php echo xlt('Assign') ?></button>
615 </div>
616 </div>
617 <div class="form-row form-inline w-100">
618 <!--<label class='font-weight-bold mx-1' for='selected_patients'><?php /*echo xlt('Location'); */ ?></label>-->
619 <?PHP
620 $searchTerm = '';
621 $ppt = array(
622 ['pid' => '0', 'ptname' => 'All Patients'],
623 ['pid' => '-1', 'ptname' => 'Repository'],
625 if (!empty($_GET['search_term']) || !empty($_GET['search'])) {
626 $searchTerm = $_GET['search_term'] ?? $_GET['search'];
628 if (!empty($searchTerm)) {
629 $ppt = $templateService->searchPatients($searchTerm);
631 $auth = '';
632 if (!empty($_REQUEST['persist_checks'])) {
633 $persist_checks = json_decode($_REQUEST['persist_checks'], true);
634 if (is_array($persist_checks)) {
635 foreach ($persist_checks as $pt) {
636 foreach ($ppt as $k => $pc) {
637 if ($pc['pid'] == $pt['pid']) {
638 unset($ppt[$k]);
639 break;
642 if (isset($pt['pid']) && isset($pt['ptname'])) {
643 $auth .= "<option value='" . attr($pt['pid']) . "' selected='selected'>" . text($pt['ptname']) . '</option>';
648 foreach ($ppt as $pt) {
649 if (!empty($from_demo_pid)) {
650 $patient = [$from_demo_pid];
652 if ((is_array($patient) && !in_array($pt['pid'], $patient)) || empty($patient)) {
653 $auth .= '<option value=' . attr($pt['pid']) . '>' . text($pt['ptname']) . '</option>';
654 } else {
655 $auth .= "<option value='" . attr($pt['pid']) . "' selected='selected'>" . text($pt['ptname'] . ' ') . '</option>';
659 <select class="form-control select-dropdown d-none" id="selected_patients" name="selected_patients[]" multiple="multiple" value="<?php echo attr($searchTerm); ?>">
660 <?php echo $auth ?>
661 </select>
662 <button id="selectSearch" class='btn btn-search btn-primary' role="button"><?php echo xlt("Search"); ?></button>
663 <button id="clearSelection" class='btn btn-secondary btn-cancel' type="button"><?php echo xlt("Clear"); ?></button>
664 </div>
665 <input type='hidden' id='upload-nav-value' name='upload-nav-value' value='<?php echo attr($_REQUEST['upload-nav-value'] ?? 'collapse') ?>' />
666 <input type='hidden' id='persist_checks' name='persist_checks' value='' />
667 <input type='hidden' id='all_state' name='all_state' value='<?php echo attr($_REQUEST['all_state'] ?? 'collapse') ?>' />
668 <input type='hidden' id='assigned_state' name='assigned_state' value='<?php echo attr($_REQUEST['assigned_state'] ?? 'collapse') ?>' />
669 <input type='hidden' id='repository_send_state' name='repository_send_state' value='<?php echo attr($_REQUEST['repository_send_state'] ?? 'collapse') ?>' />
670 <input type='hidden' id='search_term' name='search_term' value="<?php echo attr($searchTerm); ?>" />
671 </form>
672 </nav>
673 <!-- Upload -->
674 <nav class="collapse my-2 <?php echo attr($_REQUEST['upload-nav-value'] ?? '') ?>" id="upload-nav">
675 <div class='col col-12'>
676 <?php if ($authUploadTemplates) { ?>
677 <form id='form_upload' class='form-inline row' action='import_template.php' method='post' enctype='multipart/form-data'>
678 <input type="hidden" name="csrf_token_form" id="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken('import-template-upload')); ?>" />
679 <hr />
680 <div class='col'>
681 <div id='upload_scope_category'></div>
682 <div class="input-group">
683 <label class="form-check"><?php echo xlt('If questionnaire import, use Questionnaire tool'); ?>
684 <input type="checkbox" class='form-check-inline ml-1' id='upload_scope' checked>
685 </div>
686 </div>
687 <div class='form-group col'>
688 <input type='file' class='btn btn-outline-info mr-1 mt-1' id="fetch_files" name='template_files[]' multiple />
689 <div class="mt-1">
690 <button class='btn btn-outline-success d-none' type='submit' name='upload_submit' id='upload_submit' title="<?php echo xla("Import a template file or if a Questionnaire then auto create a questionnaire template."); ?>">
691 <i class='fa fa-upload mr-1' aria-hidden='true'></i><?php echo xlt("Templates"); ?></button>
692 <button class='btn btn-outline-success d-none' type='button' name='upload_submit_questionnaire' id='upload_submit_questionnaire' title="<?php echo xla("Import to the questionnaire repository for later use in encounters or FHIR API"); ?>" onclick="return resolveImport();">
693 <i class='fa fa-upload mr-1' aria-hidden='true'></i><?php echo xlt("Questionnaires Repository"); ?></button>
694 <button type='button' id='render-nav-button' name='render-nav-button' class='btn btn-save btn-outline-primary' onclick="return resolveImport('render_import_manual');" title="<?php echo xla('Used to cut and paste Questionnaire or LHC Form json. Will then convert and import to questionnaire repository.') ?>"><?php echo xlt('Manual Questionnaire') ?></button>
695 <button type='submit' id='blank-nav-button' name='blank-nav-button' class='btn btn-save btn-outline-primary' onclick="return createBlankTemplate();" title="<?php echo xla('Use this to create a new empty template for use with built in editor.') ?>"><?php echo xlt('New Empty Template') ?></button>
696 </div>
697 </div>
698 <div class="mt-2">
699 <div class="text-center m-0 p-0"><small class="my-1 font-weight-bolder font-italic"><?php echo xlt("Shows all existing Questionnaires available from repository. Select to automatically create template."); ?></small></div>
700 <div class="input-group input-group-append">
701 <select class="select-questionnaire" type="text" id="select_item" name="select_item" autocomplete="off" role="combobox" aria-expanded="false" title="<?php echo xla('Items that are already an existing template will be overwritten if selected.') ?>">
702 <option value=""></option>
703 <?php
704 $qService = new QuestionnaireService();
705 $q_list = $qService->getQuestionnaireList(false);
706 $repository_item = $_POST['select_item'] ?? null;
707 foreach ($q_list as $item) {
708 $id = attr($item['id']);
709 if ($id == $repository_item) {
710 echo "<option selected value='$id'>" . text($item['name']) . "</option>";
711 continue;
713 echo "<option value='$id'>" . text($item['name']) . "</option>";
716 </select>
717 <button type='submit' id='repository-submit' name='repository-submit' class='btn btn-save btn-success d-none' value="true"><?php echo xlt('Create') ?></button>
718 </div>
719 </div>
720 <input type='hidden' name='upload_pid' value='<?php echo attr(json_encode([-1])); ?>' />
721 <input type='hidden' name="template_category" value='<?php echo attr($category); ?>' />
722 <input type='hidden' name='upload_name' id='upload_name' value='<?php echo attr(json_encode([-1])); ?>' />
723 <input type="hidden" id="q_mode" name="q_mode" value="" />
724 <input type="hidden" id="lform" name="lform" value="" />
725 <input type="hidden" id="questionnaire" name="questionnaire" value="" />
726 </form>
727 <?php } else { ?>
728 <div class="alert alert-danger"><?php echo xlt("Not Authorized to Upload Templates") ?></div>
729 <?php } ?>
730 </div>
731 </nav>
732 <hr />
733 <!-- Repository -->
734 <div class='row'>
735 <div class='col col-12'>
736 <div class="h5"><i class='fa fa-eye mr-1' data-toggle='collapse' data-target='#repository-collapse' role='button' title="<?php echo xla('Click to expand or collapse Repository templates panel.'); ?>"></i><?php echo xlt('Template Repository') ?>
737 <span>
738 <button type='button' id='upload-nav-button' name='upload-nav-button' class='btn btn-sm btn-primary' data-toggle='collapse' data-target='#upload-nav'>
739 <i class='fa fa-upload mr-1' aria-hidden='true'></i><?php echo xlt('Upload') ?></button>
740 </span>
741 </div>
742 </div>
743 <!-- Repository table -->
744 <div class='col col-12 table-responsive <?php echo attr($_REQUEST['repository_send_state'] ?? 'collapse') ?>' id="repository-collapse">
745 <?php
746 $templates = [];
747 $show_cat_flag = false;
748 if (!empty($category)) {
749 $templates = $templateService->getTemplateListByCategory($category, -1);
750 } else {
751 $templates = $templateService->getTemplateListAllCategories(-1);
753 echo "<table class='table table-sm table-striped table-bordered'>\n";
754 echo "<thead>\n";
755 echo "<tr>\n" .
756 "<th style='width:5%'>" . xlt('Send') . "</th>" .
757 '<th>' . xlt('Category') . '</th>' .
758 "<th>" . xlt("Template Actions") . "</th>" .
759 "<th>" . xlt("Size") . "</th>" .
760 "<th>" . xlt("Last Modified") . "</th>" .
761 "</tr>\n";
762 echo "</thead>\n";
763 echo "<tbody>\n";
764 foreach ($templates as $cat => $files) {
765 if (empty($cat)) {
766 $cat = xlt('General');
768 foreach ($files as $file) {
769 $template_id = $file['id'];
770 $this_cat = $file['category'];
771 $notify_flag = false;
772 $select_cat_options = '<option value="">' . xlt('General') . "</option>\n";
773 foreach ($category_list as $option_category) {
774 if (stripos($option_category['option_id'], 'repository') !== false) {
775 continue;
777 if ($this_cat === $option_category['option_id']) {
778 $select_cat_options .= "<option value='" . attr($option_category['option_id']) . "' selected>" . text($option_category['title']) . "</option>\n";
779 } else {
780 $select_cat_options .= "<option value='" . attr($option_category['option_id']) . "'>" . text($option_category['title']) . "</option>\n";
783 echo "<tr>";
784 if ($file['mime'] == 'application/pdf') {
785 $this_cat = xlt('PDF Document');
786 $notify_flag = true;
787 echo '<td>' . '*' . '</td>';
788 echo "<td>" . $this_cat . " Id: " . attr($template_id) . "</td>";
789 } else {
790 echo "<td><input type='checkbox' class='form-check-inline' name='send' value='" . attr($template_id) . "' /></td>";
791 echo '<td><select class="form-control form-control-sm" id="category_table' . attr($template_id) .
792 '" onchange="updateCategory(' . attr_js($template_id) . ')" value="' . attr($this_cat) . '">' .
793 $select_cat_options . '</select></td>';
795 echo '<td>' .
796 '<button id="templateEdit' . attr($template_id) .
797 '" class="btn btn-sm btn-outline-primary" onclick="templateEdit(' . attr_js($template_id) . ',' . attr_js($notify_flag) . ')" type="button">' . text($file['template_name']) .
798 '</button>';
799 if ($authUploadTemplates) {
800 echo '<button id="templateDelete' . attr($template_id) .
801 '" class="btn btn-sm btn-outline-danger float-right" onclick="templateDelete(' . attr_js($template_id) . ',' . attr_js($file['template_name']) . ')" type="button">' . xlt("Delete") .
802 '</button>';
804 echo "</td>";
805 echo "<td>" . text($file['size']) . "</td>";
806 echo "<td>" . text(date('m/d/Y H:i:s', strtotime($file['modified_date']))) . "</td>";
807 echo "</tr>";
809 <?php
812 if (empty($template_id)) {
813 echo '<tr><td></td><td>' . $none_message . "</td></tr>\n";
815 echo "</tbody>\n";
816 echo "</table>\n";
818 <div>
819 <?php
820 echo "<table class='table table-sm table-striped table-bordered'>\n";
821 echo '<caption>' . xlt('Profiles in Portal') . "</caption>";
822 echo "<thead>\n";
823 echo "<tr>\n" .
824 "<th>" . xlt('Active') . "<button type='button' id='send-profile-hide' class='btn btn-sm ml-1 py-0 btn-transmit btn-success d-none' onclick='return sendProfiles()'>" . xlt('Update') . "</button></th>" .
825 '<th style="min-width: 25%">' . xlt('Profile') . '</th>' .
826 '<th>' . xlt('Assigned Templates') . '</th>' .
827 '<th>' . xlt('Assigned Groups') . '</th>' .
828 "</tr>\n";
829 echo "</thead>\n";
830 foreach ($profile_list as $profile => $profiles) {
831 $template_list = '';
832 $group_list_text = '';
833 $group_items_list = $templateService->getPatientGroupsByProfile($profile);
834 $profile_items_list = $templateService->getTemplateListByProfile($profile);
835 if (empty($profile_items_list)) {
836 continue;
838 $total = 0;
839 foreach ($profile_items_list as $key => $files) {
840 $total += count($files ?? []);
841 foreach ($files as $file) {
842 if (is_array($file)) {
843 $template_list .= $file['template_name'] . ', ';
847 $template_list = substr($template_list, 0, -2);
848 $profile_esc = attr($profile);
849 foreach ($group_items_list as $key => $groups) {
850 foreach ($groups as $group) {
851 if (is_array($group)) {
852 $group_list_text .= $group_list[$group['member_of']]['title'] . ', ';
856 $group_list_text = substr($group_list_text, 0, -2);
857 $send = 'send';
858 if (!empty($group_list_text)) {
859 $send = 'send_profile';
861 echo '<tr>';
862 $is_checked = '';
863 if ((int)$templateService->fetchProfileStatus($profiles['option_id']) === 1) {
864 $is_checked = 'checked';
866 echo "<td><input type='checkbox' class='form-check-inline' $is_checked name='" . attr($send) . "' data-send_profile='yes' value='" . $profile_esc . "' /></td>";
867 echo '<td>' . text($profiles['title']) . '</td>';
868 echo '<td><em>' . text($template_list) . '</em></td>';
869 echo '<td><em>' . text($group_list_text) . '</em></td>';
870 echo '</tr>';
872 if (empty($profile_list)) {
873 echo '<tr><td></td><td>' . $none_message . "</td></tr>\n";
875 echo "</tbody>\n";
876 echo "</table>\n";
878 </div>
879 </div>
880 </div>
881 <!-- All Patients -->
882 <hr />
883 <div class='row'>
884 <div class='col col-12' data-toggle='collapse' data-target='#template-collapse'>
885 <h5><i class='fa fa-eye mr-1' role='button' title="<?php echo xla('Click to expand or collapse All active patient templates panel.'); ?>"></i><?php echo '' . xlt('Default Patient Templates') . '' ?></h5>
886 </div>
887 <div class='col col-12 table-responsive <?php echo attr(($_REQUEST['all_state'] ?? '') ?: 'collapse') ?>' id='template-collapse'>
888 <?php
889 $templates = [];
890 $show_cat_flag = false;
891 if (!empty($category)) {
892 $templates = $templateService->getTemplateListByCategory($category);
893 } else {
894 $templates = $templateService->getTemplateListAllCategories();
896 echo "<table class='table table-sm table-striped table-bordered'>\n";
897 echo "<thead>\n";
898 echo "<tr>\n" .
899 '<th>' . xlt('Category') . '</th>' .
900 '<th>' . xlt('Template Actions') . '</th>' .
901 '<th>' . xlt('Size') . '</th>' .
902 '<th>' . xlt('Created') . '</th>' .
903 '<th>' . xlt('Last Modified') . '</th>' .
904 "</tr>\n";
905 echo "</thead>\n";
906 echo "<tbody>\n";
907 foreach ($templates as $cat => $files) {
908 if (empty($cat)) {
909 $cat = xlt('General');
911 foreach ($files as $file) {
912 $template_id = $file['id'];
913 echo '<tr>';
914 /*echo "<td><input type='checkbox' class='form-check-inline' id='send' name='send' value='" . attr($template_id) . "' /></td>";*/
915 echo '<td>' . text(ucwords($cat)) . '</td><td>';
916 echo '<button id="templateEdit' . attr($template_id) .
917 '" class="btn btn-sm btn-outline-primary" onclick="templateEdit(' . attr_js($template_id) . ')" type="button">' . text($file['template_name']) . '</button>';
918 if ($authUploadTemplates) {
919 echo '<button id="templateDelete' . attr($template_id) .
920 '" class="btn btn-sm btn-outline-danger" onclick="templateDelete(' . attr_js($template_id) . ')" type="button">' . xlt('Delete') . '</button>';
922 echo '<td>' . text($file['size']) . '</td>';
923 echo '<td>' . text(date('m/d/Y H:i:s', strtotime($file['modified_date']))) . '</td>';
924 echo '</tr>';
926 <?php
929 if (empty($files)) {
930 echo '<tr><td>' . $none_message . "</td></tr>\n";
932 echo "</tbody>\n";
933 echo "</table>\n";
935 </div>
936 </div>
937 <hr />
938 <div class='row'>
939 <div class='col col-12'>
940 <div class='h5'>
941 <i class='fa fa-eye mr-1' data-toggle='collapse' data-target='#assigned_collapse' role='button' title="<?php echo xla('Click to expand or collapse Assigned Patients panel.'); ?>"></i><?php echo xlt('Patient Assigned Templates') ?>
942 </div>
943 </div>
944 <!-- Assigned table -->
945 <div class='col col-12 table-responsive <?php echo attr(($_REQUEST['assigned_state'] ?? '') ?: 'collapse') ?>' id="assigned_collapse">
946 <?php
947 // by categories and patient pid.
948 $templates = [];
949 $show_cat_flag = false;
950 if (is_array($patient) && $patient[0] === '0') {// All templates for all patients
951 $patient_templates = $templateService->getPortalAssignedTemplates(0, $category, false);
952 } else {// Category selected so get all of them for pid's
953 $patient_templates = $templateService->getTemplateCategoriesByPids($patient, $category);
955 echo "<table class='table table-sm table-bordered'>\n";
956 echo "<tbody>";
957 $idcnt = 0;
958 foreach ($patient_templates as $name => $templates) {
959 $count = 0;
960 $fetched_groups = $fetch_pid = null;
961 foreach ($templates as $c => $t) {
962 if (is_array($t)) {
963 $fetch_pid = $t[0]['pid'];
964 if (empty($fetched_groups)) {
965 $fetched_groups = str_replace('|', ', ', $t[0]['patient_groups'] ?? '');
967 $count += count($t);
971 echo "<tr><td class='h6 font-weight-bolder bg-light text-dark' data-toggle='collapse' data-target='" .
972 attr('#id' . ++$idcnt) . "' role='button'>" . text($name) .
973 " (" . text($count . ' ' . xl('Templates')) . ") in " . text($fetched_groups) . "</td></tr>";
974 echo "<td class='collapse' id='" . attr('id' . $idcnt) . "'><table class='table table-sm table-striped table-bordered'>\n";
975 //echo '<caption><h5>' . text($name) . '</h5></caption>';
976 echo "<thead>\n";
977 echo "<tr>\n" .
978 '<th>' . xlt('Category') . '</th>' .
979 '<th>' . xlt('Profile') . '</th>' .
980 '<th>' . xlt('Template Actions') . '</th>' .
981 '<th>' . xlt('Status') . '</th>' .
982 '<th>' . xlt('Last Action') . '</th>' .
983 '<th>' . xlt('Next Due') . '</th>' .
984 "</tr>\n";
985 echo "</thead>\n";
986 echo "<tbody>\n";
987 foreach ($templates as $cat => $files) {
988 if (empty($cat)) {
989 $cat = xlt('General');
991 foreach ($files as $file) {
992 $template_id = $file['id'];
994 $audit_status = $audit_status_blank;
995 $audit_status_fetch = $templateService->fetchPatientDocumentStatus($file['pid'], $file['id']);
996 if (is_array($audit_status_fetch)) {
997 $audit_status = array_merge($audit_status_blank, $file, $audit_status_fetch);
998 } else {
999 $audit_status = array_merge($audit_status_blank, $file);
1001 $last_date = $audit_status['create_date'] ?? '' ?: $file['modified_date'] ?? '';
1002 $next_due = $templateService->showTemplateFromEvent($file, true);
1003 $action_status = '';
1004 if ($next_due > 1) {
1005 if ($audit_status['denial_reason'] === 'In Review') {
1006 $action_status = xl('Scheduled but Needs Review');
1007 } else {
1008 $action_status = xl('Scheduled');
1010 $next_due = date('m/d/Y', $next_due);
1011 } elseif ($next_due === 1 || ($next_due === true && ($file['recurring'] ?? 0))) {
1012 if ($audit_status['denial_reason'] === 'In Review') {
1013 $action_status = xl('In audit. Needs Review');
1014 } else {
1015 $action_status = xl('Recurring');
1017 $next_due = xl('Active');
1018 } elseif ($next_due === 0) {
1019 $action_status = xl('Completed');
1020 $next_due = xl('Inactive');
1021 } elseif ($next_due === true && empty($file['recurring'] ?? 0)) {
1022 $next_due = xl('Active');
1024 echo '<tr><td>' . text(ucwords($cat)) . '</td>';
1025 echo '<td>' . text($profile_list[$file['profile']]['title'] ?? '') . '</td>';
1026 echo '<td>' .
1027 '<button type="button" id="patientEdit' . attr($template_id) .
1028 '" class="btn btn-sm btn-outline-primary" onclick="templateEdit(' . attr_js($template_id) . ')" title="' . xla("Click to edit in editor.") . '">' .
1029 text($file['template_name']) . "</button>\n";
1030 if ($authUploadTemplates && $cat == 'questionnaire' && !empty($audit_status['encounter'])) {
1031 echo '<button type="button" id="patientView' . attr($template_id) .
1032 '" class="btn btn-sm btn-outline-success" onclick="questionnaireViewCurrent(' . attr_js($audit_status['encounter']) . ')">' .
1033 xlt("View") . "</button>\n";
1035 if ($authUploadTemplates && empty($file['member_of']) && !empty($file['status'])) {
1036 echo '<button type="button" id="patientDelete' . attr($template_id) .
1037 '" class="btn btn-sm btn-outline-danger" onclick="templateDelete(' . attr_js($template_id) . ')">' . xlt('Delete') . "</button>\n";
1039 // onetime button for template.
1040 $file['onetime_period'] = "P2D";
1041 $file['is_onetime'] = 1;
1042 $file['audit_id'] = 0;
1043 if ($audit_status['denial_reason'] == 'In Review' || $audit_status['denial_reason'] == 'Editing') {
1044 $file['audit_id'] = $audit_status['audit_id'] ?? 0;
1046 $e_pid = $fetch_pid ?: $file['pid'];
1047 if (!empty($e_pid)) {
1048 $eventDispatcher->dispatch(new SendNotificationEvent($e_pid, $file), SendNotificationEvent::ACTIONS_RENDER_NOTIFICATION_POST);
1051 echo '</td><td>' . text($action_status) . '</td>';
1052 echo '<td>' . text(date('m/d/Y H:i:s', strtotime($last_date))) . '</td>';
1053 echo '<td>' . text($next_due) . '</td>';
1054 echo "</tr>\n";
1057 echo "</tbody>\n";
1058 echo "</table></td>\n";
1060 if (empty($templates)) {
1061 echo '<tr><td>' . xlt('Multi Select Patients or All Patients using toolbar Location') . "</td></tr>\n";
1063 echo "</tbody>\n";
1064 echo "</table>\n";
1066 </div>
1067 </div>
1068 <hr />
1069 </div>
1070 </div>
1071 </body>
1072 </html>