chore(deps): bump twig/twig from 3.17.1 to 3.19.0 (#7951)
[openemr.git] / portal / import_template.php
blobbe4d056bb370845ad572bc546e11f58ff0fa8b52
1 <?php
3 /**
4 * import_template.php
6 * @package OpenEMR
7 * @link https://www.open-emr.org
8 * @author Jerry Padgett <sjpadgett@gmail.com>
9 * @copyright Copyright (c) 2016-2023 Jerry Padgett <sjpadgett@gmail.com>
10 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
13 require_once("../interface/globals.php");
15 use OpenEMR\Common\Acl\AclMain;
16 use OpenEMR\Common\Csrf\CsrfUtils;
17 use OpenEMR\Core\Header;
18 use OpenEMR\Services\DocumentTemplates\DocumentTemplateService;
19 use OpenEMR\Services\QuestionnaireService;
21 if (!(isset($GLOBALS['portal_onsite_two_enable'])) || !($GLOBALS['portal_onsite_two_enable'])) {
22 echo xlt('Patient Portal is turned off');
23 exit;
26 $authUploadTemplates = AclMain::aclCheckCore('admin', 'forms');
27 $templateService = new DocumentTemplateService();
28 $patient = json_decode($_POST['upload_pid'] ?? '');
29 $template_content = null;
31 if (($_POST['mode'] ?? null) === 'save_profiles') {
32 $profiles = json_decode($_POST['profiles'], true);
33 $rtn = $templateService->saveAllProfileTemplates($profiles);
34 if ($rtn) {
35 echo xlt("Profiles successfully saved.");
36 } else {
37 echo xlt('Error! Profiles save failed. Check your Profile lists.');
39 exit;
42 if (($_REQUEST['mode'] ?? null) === 'render_profile') {
43 echo renderProfileHtml();
44 exit;
47 if (($_REQUEST['mode'] ?? null) === 'getPdf') {
48 if ($_REQUEST['docid']) {
49 $template = $templateService->fetchTemplate($_REQUEST['docid']);
50 echo "data:application/pdf;base64," . base64_encode($template['template_content']);
51 exit();
53 die(xlt('Invalid File'));
56 if (($_POST['mode'] ?? null) === 'get') {
57 if ($_REQUEST['docid']) {
58 $template = $templateService->fetchTemplate($_POST['docid']);
59 echo $template['template_content'];
60 exit();
62 die(xlt('Invalid File'));
65 if (($_POST['mode'] ?? null) === 'send_profiles') {
66 if (!empty($_POST['checked'])) {
67 $profiles = json_decode($_POST['checked']) ?: [];
68 $last_id = $templateService->setProfileActiveStatus($profiles);
69 if ($last_id) {
70 echo xlt('Profile Templates Successfully set to Active in portal.');
71 } else {
72 echo xlt('Error. Problem setting one or more profiles.');
74 exit;
76 die(xlt('Invalid Request'));
79 if (($_POST['mode'] ?? null) === 'send') {
80 if (!empty($_POST['docid'])) {
81 $pids_array = json_decode($_POST['docid']) ?: ['0'];
82 // profiles are in an array with flag to indicate a group of template id's
83 $ids = json_decode($_POST['checked']) ?: [];
84 $master_ids = [];
85 foreach ($ids as $id) {
86 if (is_array($id)) {
87 if ($id[1] !== true) {
88 continue;
90 $profile = $id[0];
91 // get all template ids for this profile
92 $rtn_ids = sqlStatement('SELECT `template_id` as id FROM `document_template_profiles` WHERE `profile` = ? AND `template_id` > "0"', array($profile));
93 while ($rtn_id = sqlFetchArray($rtn_ids)) {
94 $master_ids[$rtn_id['id']] = $profile;
96 continue;
98 $master_ids[$id] = '';
100 $last_id = $templateService->sendTemplate($pids_array, $master_ids, $_POST['category']);
101 if ($last_id) {
102 echo xlt('Templates Successfully sent to Locations.');
103 } else {
104 echo xlt('Error. Problem sending one or more templates.');
106 exit;
108 die(xlt('Invalid Request'));
111 if (($_POST['mode'] ?? null) === 'save') {
112 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"], 'import-template-save')) {
113 CsrfUtils::csrfNotVerified();
115 if (!$authUploadTemplates) {
116 die(xlt('Not authorized to edit template'));
118 if ($_POST['docid']) {
119 if (stripos($_POST['content'], "<?php") === false) {
120 $template = $templateService->updateTemplateContent($_POST['docid'], $_POST['content']);
121 if ($_POST['service'] === 'window') {
122 echo "<script>if (typeof parent.dlgopen === 'undefined') window.close(); else parent.dlgclose();</script>";
124 } else {
125 die(xlt('Invalid Content'));
127 } else {
128 die(xlt('Invalid File'));
130 } elseif (($_POST['mode'] ?? null) === 'delete') {
131 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"], 'import-template-delete')) {
132 CsrfUtils::csrfNotVerified();
134 if (!$authUploadTemplates) {
135 die(xlt('Not authorized to delete template'));
137 if ($_POST['docid']) {
138 $template = $templateService->deleteTemplate($_POST['docid'], ($_POST['template'] ?? null));
139 exit($template);
141 die(xlt('Invalid File'));
142 } elseif (($_POST['mode'] ?? null) === 'update_category') {
143 if ($_POST['docid']) {
144 $template = $templateService->updateTemplateCategory($_POST['docid'], $_POST['category']);
145 echo xlt('Template Category successfully changed to new Category') . ' ' . text($_POST['category']);
146 exit;
148 die(xlt('Invalid Request Parameters'));
151 if (isset($_POST['blank-nav-button'])) {
152 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"], 'import-template-upload')) {
153 CsrfUtils::csrfNotVerified();
155 if (!$authUploadTemplates) {
156 xlt("Not Authorized to Upload Templates");
157 exit;
159 $is_blank = isset($_POST['blank-nav-button']);
160 $upload_name = $_POST['upload_name'] ?? '';
161 $category = $_POST['template_category'] ?? '';
162 $patient = '-1';
163 if (!empty($upload_name)) {
164 $name = preg_replace("/[^A-Z0-9.]/i", " ", $upload_name);
165 try {
166 $content = "{ParseAsHTML}";
167 $success = $templateService->insertTemplate($patient, $category, $upload_name, $content, 'application/text');
168 if (!$success) {
169 header('refresh:3;url= import_template_ui.php');
170 echo "<h4 style='color:red;'>" . xlt("New template save failed. Try again.") . "</h4>";
171 exit;
173 } catch (Exception $e) {
174 header('refresh:3;url= import_template_ui.php');
175 echo '<h3>' . xlt('Error') . "</h3><h4 style='color:red;'>" .
176 text($e->getMessage()) . '</h4>';
177 exit;
180 header("location: " . $_SERVER['HTTP_REFERER']);
181 die();
184 if (isset($_REQUEST['q_mode']) && !empty($_REQUEST['q_mode'])) {
185 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"], 'import-template-upload')) {
186 CsrfUtils::csrfNotVerified();
188 if (!$authUploadTemplates) {
189 xlt("Not Authorized to Upload Templates");
190 exit;
192 $id = 0;
193 $q = $_POST['questionnaire'] ?? '';
194 $l = $_POST['lform'] ?? '';
195 if (!empty($q)) {
196 $service = new QuestionnaireService();
197 try {
198 $id = $service->saveQuestionnaireResource($q, null, null, null, $l);
199 } catch (Exception $e) {
200 header('refresh:3;url= import_template_ui.php');
201 echo '<h3>' . xlt('Error') . "</h3><h4 style='color:red;'>" .
202 text($e->getMessage()) . '</h4>';
203 exit;
205 if (empty($id)) {
206 header('refresh:3;url= import_template_ui.php');
207 echo '<h3>' . xlt('Error') . "</h3><h4 style='color:red;'>" .
208 xlt("Import failed to save.") . '</h4>';
209 exit;
212 header("location: " . $_SERVER['HTTP_REFERER']);
213 die();
216 // templates file import
217 if ((count($_FILES['template_files']['name'] ?? []) > 0) && !empty($_FILES['template_files']['name'][0] ?? '')) {
218 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"], 'import-template-upload')) {
219 CsrfUtils::csrfNotVerified();
221 if (!$authUploadTemplates) {
222 xlt("Not Authorized to Upload Templates");
223 exit;
225 // so it is a template file import. create record(s).
226 $import_files = $_FILES["template_files"];
227 $total = count($_FILES['template_files']['name']);
228 for ($i = 0; $i < $total; $i++) {
229 if ($_FILES['template_files']['error'][$i] !== UPLOAD_ERR_OK) {
230 header('refresh:3;url= import_template_ui.php');
231 echo '<h3>' . xlt('Error') . "</h3><h4 style='color:red;'>" .
232 xlt('An error occurred: Missing file to upload. Returning to form.') . '</h4>';
233 exit;
235 // parse out what we need
236 $name = preg_replace("/[^A-Z0-9.]/i", " ", $_FILES['template_files']['name'][$i]);
237 if (preg_match("/(.*)\.(php|php7|php8|doc|docx)$/i", $name) !== 0) {
238 die(xlt('Invalid file type.'));
240 $parts = pathinfo($name);
241 $name = ucwords(strtolower($parts["filename"]));
242 if (empty($patient)) {
243 $patient = ['-1'];
245 // get em and dispose
246 try {
247 $success = $templateService->uploadTemplate($name, $_POST['template_category'], $_FILES['template_files']['tmp_name'][$i], $patient, isset($_POST['upload_submit_questionnaire']));
248 if (!$success) {
249 echo "<p>" . xlt("Unable to save files. Use back button!") . "</p>";
250 exit;
252 } catch (Exception $e) {
253 header('refresh:3;url= import_template_ui.php');
254 echo '<h3>' . xlt('Error') . "</h3><h4 style='color:red;'>" .
255 text($e->getMessage()) . '</h4>';
256 exit;
259 header("location: " . $_SERVER['HTTP_REFERER']);
260 die();
263 if (isset($_POST['repository-submit']) && !empty($_POST['upload_name'] ?? '')) {
264 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"], 'import-template-upload')) {
265 CsrfUtils::csrfNotVerified();
267 if (!$authUploadTemplates) {
268 xlt("Not Authorized to Upload Templates");
269 exit;
271 $selected_q = (int)($_POST['select_item'] ?? 0);
272 $upload_name = $_POST['upload_name'] ?? '';
273 $category = $_POST['template_category'] ?? '';
274 if (empty($category)) {
275 $category = 'questionnaire';
277 if (empty($patient) || $patient === [-1]) {
278 $patient = '-1';
280 if (!empty($upload_name)) {
281 // will use same name as questionnaire from repository
282 try {
283 $content = "{ParseAsHTML}{Questionnaire:$selected_q}" . "\n";
284 $mimetype = 'application/text';
285 $success = $templateService->insertTemplate($patient, $category, $upload_name, $content, 'application/text');
286 if (!$success) {
287 header('refresh:3;url= import_template_ui.php');
288 echo "<h4 style='color:red;'>" . xlt("New template save failed. Try again.") . "</h4>";
289 exit;
291 } catch (Exception $e) {
292 header('refresh:3;url= import_template_ui.php');
293 echo '<h3>' . xlt('Error') . "</h3><h4 style='color:red;'>" .
294 text($e->getMessage()) . '</h4>';
295 exit;
298 header("location: " . $_SERVER['HTTP_REFERER']);
299 die();
302 if (($_REQUEST['mode'] ?? '') === 'editor_render_html') {
303 if ($_REQUEST['docid']) {
304 $content = $templateService->fetchTemplate($_REQUEST['docid']);
305 $template_content = $content['template_content'];
306 if ($content['mime'] === 'application/pdf') {
307 $content = "<iframe width='100%' height='100%' src='data:application/pdf;base64, " .
308 attr(base64_encode($template_content)) . "'></iframe>";
309 echo $content;
310 exit;
312 renderEditorHtml($_REQUEST['docid'], $template_content);
313 } else {
314 die(xlt('Invalid File'));
316 } elseif (!empty($_GET['templateHtml'] ?? null)) {
317 renderEditorHtml($_REQUEST['docid'], $_GET['templateHtml']);
321 * @param $template_id
322 * @param $content
324 function renderEditorHtml($template_id, $content)
326 global $authUploadTemplates;
328 $lists = [
329 '{ParseAsHTML}', '{ParseAsText}', '{styleBlockStart}', '{styleBlockEnd}', '{SignaturesRequired}', '{TextInput}', '{sizedTextInput:120px}', '{smTextInput}', '{TextBox:03x080}', '{CheckMark}', '{RadioGroup:option1_many...}', '{RadioGroupInline:option1_many...}', '{ynRadioGroup}', '{TrueFalseRadioGroup}', '{DatePicker}', '{DateTimePicker}', '{StandardDatePicker}', '{CurrentDate:"global"}', '{CurrentTime}', '{DOS}', '{ReferringDOC}', '{PatientID}', '{PatientName}', '{PatientSex}', '{PatientDOB}', '{PatientPhone}', '{Address}', '{City}', '{State}', '{Zip}', '{PatientSignature}', '{AdminSignature}', '{WitnessSignature}', '{AcknowledgePdf:pdf name or id:title}', '{EncounterForm:LBF}', '{Questionnaire:name or id}', '{Medications}', '{ProblemList}', '{Allergies}', '{ChiefComplaint}', '{DEM: }', '{HIS: }', '{LBF: }', '{GRP}{/GRP}'
332 <!DOCTYPE html>
333 <html>
334 <head>
335 <?php Header::setupHeader(['summernote']); ?>
336 </head>
337 <style>
338 input:focus,
339 input:active {
340 outline: 0 !important;
341 -webkit-appearance: none;
342 box-shadow: none !important;
345 .list-group-item {
346 font-size: .9rem;
349 .note-editable {
350 height: 78vh !important;
352 </style>
353 <body>
354 <div class="container-fluid">
355 <div class="row">
356 <div class="col-10 px-1 sticky-top">
357 <form class="sticky-top" action='./import_template.php' method='post'>
358 <input type="hidden" name="csrf_token_form" id="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken('import-template-save')); ?>" />
359 <input type="hidden" name="docid" value="<?php echo attr($template_id) ?>">
360 <input type='hidden' name='mode' value="save">
361 <input type='hidden' name='service' value='window'>
362 <textarea cols='80' rows='10' id='templateContent' name='content'><?php echo text($content) ?></textarea>
363 <div class="row btn-group mt-1 float-right">
364 <div class='col btn-group mt-1 float-right'>
365 <?php if ($authUploadTemplates) { ?>
366 <button type="submit" class="btn btn-sm btn-primary"><?php echo xlt("Save"); ?></button>
367 <?php } else { ?>
368 <button disabled title="<?php echo xla("Not Authorized to Edit Templates") ?>" type="submit" class="btn btn-sm btn-primary"><?php echo xlt("Save"); ?></button>
369 <?php } ?>
370 <button type='button' class='btn btn-sm btn-secondary' onclick='parent.window.close() || parent.dlgclose()'><?php echo xlt('Cancel'); ?></button>
371 </div>
372 </div>
373 </form>
374 </div>
375 <div class="col-sm-2 px-0">
376 <div class='h4'><?php echo xlt("Directives") ?></div>
377 <ul class='list-group list-group-flush pl-1 mb-5'>
378 <?php
379 foreach ($lists as $list) {
380 echo '<input class="list-group-item p-1" value="' . attr($list) . '">';
383 </ul>
384 </div>
385 </div>
386 </div>
387 </body>
388 <script>
389 let isDialog = false;
390 let height = 550;
391 let max = 680;
392 <?php if (!empty($_REQUEST['dialog'] ?? '')) { ?>
393 isDialog = true;
394 height = 425;
395 max = 600;
396 <?php } ?>
397 let editor = '';
398 document.addEventListener('DOMContentLoaded', function () {
399 document.querySelectorAll('.list-group-item').forEach(item => {
400 item.addEventListener('mouseup', event => {
401 let input = event.currentTarget;
402 input.focus();
403 input.select();
407 $(function () {
408 $('#templateContent').summernote({
409 placeholder: 'Start typing here...',
410 height: 550,
411 minHeight: 300,
412 maxHeight: 800,
413 width: '100%',
414 tabsize: 4,
415 focus: true,
416 disableDragAndDrop: true,
417 dialogsInBody: true,
418 dialogsFade: true
421 </script>
422 <script>
423 </script>
424 </html>
425 <?php }
430 function renderProfileHtml()
432 global $templateService;
434 $category_list = $templateService->fetchDefaultCategories();
435 $profile_list = $templateService->fetchDefaultProfiles();
437 <!DOCTYPE html>
438 <html>
439 <head>
440 <?php
441 if (empty($GLOBALS['openemr_version'] ?? null)) {
442 Header::setupHeader(['opener', 'sortablejs']);
443 } else {
444 Header::setupHeader(['opener']); ?>
445 <script src="<?php echo $GLOBALS['web_root']; ?>/portal/public/assets/sortablejs/Sortable.min.js?v=<?php echo $GLOBALS['v_js_includes']; ?>"></script>
446 <?php } ?>
447 </head>
448 <style>
449 body {
450 overflow: hidden;
453 .list-group-item {
454 cursor: move;
457 strong {
458 font-weight: 600;
461 .col-height {
462 max-height: 95vh;
463 overflow-y: auto;
464 overflow-x: hidden;
467 .note-editor.dragover .note-dropzone {
468 display: none
470 </style>
471 <script>
472 const profiles = <?php echo js_escape($profile_list); ?>;
473 document.addEventListener('DOMContentLoaded', function () {
474 // init drag and drop
475 let repository = document.getElementById('drag_repository');
476 Sortable.create(repository, {
477 group: {
478 name: 'repo',
479 handle: '.move-handle',
480 pull: 'clone'
482 sort: true,
483 animation: 150,
484 onAdd: function (evt) {
485 let el = evt.item;
486 el.parentNode.removeChild(el);
490 Object.keys(profiles).forEach(key => {
491 let profileEl = profiles[key]['option_id']
492 let id = document.getElementById(profileEl);
493 Sortable.create(id, {
494 group: {
495 name: 'repo',
496 delay: 1000,
497 handle: '.move-handle',
498 put: (to, from, dragEl, event) => {
499 for (let i = 0; i < to.el.children.length; i++) {
500 if (to.el.children[i].getAttribute('data-id') === dragEl.getAttribute('data-id')) {
501 return false
504 return true
507 onAdd: function (evt) {
508 let el = evt.item;
509 el.getElementsByTagName('form')[0].classList.remove("d-none");
511 animation: 150
515 top.restoreSession();
517 function submitProfiles() {
518 top.restoreSession();
519 let target = document.getElementById('edit-profiles');
520 let profileTarget = target.querySelectorAll('ul');
521 let formTarget = target.querySelectorAll('form');
522 let profileArray = [];
523 let listData = {};
524 profileTarget.forEach((ulItem, index) => {
525 let lists = ulItem.querySelectorAll('li');
526 lists.forEach((item, index) => {
527 //console.log({index, item})
528 let pform = item.getElementsByTagName('form')[0];
529 let formData = $(pform).serializeArray();
530 listData = {
531 'form': formData,
532 'profile': ulItem.dataset.profile,
533 'id': item.dataset.id,
534 'category': item.dataset.category,
535 'name': item.dataset.name
537 profileArray.push(listData);
540 const data = new FormData();
541 data.append('profiles', JSON.stringify(profileArray));
542 data.append('mode', 'save_profiles');
543 fetch('./import_template.php', {
544 method: 'POST',
545 body: data,
546 }).then(rtn => rtn.text()).then((rtn) => {
547 (async (time) => {
548 await asyncAlertMsg(rtn, time, 'success', 'lg');
549 })(1000).then(rtn => {
550 opener.document.edit_form.submit();
551 dlgclose();
553 }).catch((error) => {
554 console.error('Error:', error);
557 </script>
558 <body>
559 <div class='container-fluid'>
560 <?php
561 // exclude templates sent to all patients(defaults)
562 $templates = $templateService->getTemplateListAllCategories(-1, true);
563 //$templates = $templateService->getTemplateListUnique(); // Reserved TBD future use
565 <div class='row'>
566 <div class='col-6 col-height'>
567 <nav id='disposeProfile' class='navbar navbar-light bg-light sticky-top'>
568 <div class='btn-group'>
569 <button class='btn btn-primary btn-save btn-sm' onclick='return submitProfiles();'><?php echo xlt('Save Profiles'); ?></button>
570 <button class='btn btn-secondary btn-cancel btn-sm' onclick='dlgclose();'><?php echo xlt('Quit'); ?></button>
571 </div>
572 </nav>
573 <div class="border-left border-right">
574 <div class='bg-dark text-light py-1 mb-2 text-center'><?php echo xlt('Available Templates'); ?></div>
575 <ul id='drag_repository' class='list-group mx-2 mb-2'>
576 <?php
577 foreach ($templates as $cat => $files) {
578 if (empty($cat)) {
579 $cat = xlt('General');
581 foreach ($files as $file) {
582 $template_id = attr($file['id']);
583 $title = $category_list[$cat]['title'] ?: $cat;
584 $title_esc = attr($title);
585 $this_name = attr($file['template_name']);
586 if ($file['mime'] === 'application/pdf') {
587 continue;
589 /* The drag container */
590 echo "<li class='list-group-item px-1 py-1 mb-1 bg-primary' data-id='$template_id' data-name='$this_name' data-category='$title_esc'>" .
591 "<strong>" . text($file['template_name']) .
592 '</strong>' . ' ' . xlt('in category') . ' ' .
593 '<strong>' . text($title) . '</strong>';
595 <form class='form form-inline bg-light text-dark py-1 pl-1 d-none'>
596 <div class='input-group-sm input-group-prepend'>
597 <label class="form-check-inline d-none"><?php echo xlt('OneTime') ?>
598 <input name="onetimeIsOkay" type='checkbox' class="input-control-sm ml-1 mt-1" title="<?php echo xla('Enable Auto Portal log in for presenting document to patient.') ?>" />
599 </label>
600 </div>
601 <label class='font-weight-bold mr-1 d-none'><?php echo xlt('Notify') ?></label>
602 <div class='input-group-sm input-group-prepend d-none'>
603 <input name="notify_days" type="text" style="width: 50px;" class='input-control-sm ml-1' placeholder="<?php echo xla('days') ?>" value="" />
604 <label class="mx-1"><?php echo xlt('Days') ?></label>
605 </div>
606 <div class='input-group-sm input-group-prepend'>
607 <select name="notify_when" class='input-control-sm mx-1 d-none'>
608 <option value=""><?php echo xlt('Unassigned'); ?></option>
609 <option value="new"><?php echo xlt('New'); ?></option>
610 <option value='before_appointment'><?php echo xlt('Before Appointment'); ?></option>
611 <option value='after_appointment'><?php echo xlt('After Appointment'); ?></option>
612 <option value="before_expires"><?php echo xlt('Before Expires'); ?></option>
613 <option value="in_edit"><?php echo xlt('In Edit'); ?></option>
614 </select>
615 </div>
616 <div class='input-group-sm input-group-prepend'>
617 <label class="form-check-inline"><?php echo xlt('Recurring') ?>
618 <input name="recurring" type='checkbox' class="input-control-sm ml-1 mt-1" />
619 </label>
620 </div>
621 <div class='input-group-sm input-group-prepend'>
622 <label><?php echo xlt('On') ?></label>
623 <select name="when" class='input-control-sm mx-1'>
624 <!--<option value=""><?php /*echo xlt('Unassigned') */ ?></option>-->
625 <option value="completed"><?php echo xlt('Completed') ?></option>
626 <option value='always'><?php echo xlt('Always') ?></option>
627 <option value='once'><?php echo xlt('One time') ?></option>
628 </select>
629 </div>
630 <div class='input-group-sm input-group-prepend'>
631 <label><?php echo xlt('Every') ?></label>
632 <input name="days" type="text" style="width: 50px;" class='input-control-sm ml-1' placeholder="<?php echo xla('days') ?>" value="" />
633 <label class="mx-1"><?php echo xlt('Days') ?></label>
634 </div>
635 </form>
636 <?php
637 echo '</li>' . "\n";
641 </ul>
642 </div>
643 </div>
644 <div class='col-6 col-height'>
645 <div id="edit-profiles" class='control-group mx-1 border-left border-right'>
646 <?php
647 foreach ($profile_list as $profile => $profiles) {
648 $profile_items_list = $templateService->getTemplateListByProfile($profile);
649 $profile_esc = attr($profile);
651 <div class='bg-dark text-light mb-1 py-1 pl-1'><?php echo xlt($profiles['title']) ?></div>
652 <?php
653 echo "<ul id='$profile_esc' class='list-group mx-2 mb-2' data-profile='$profile_esc'>\n";
654 foreach ($profile_items_list as $cat => $files) {
655 if (empty($cat)) {
656 $cat = xlt('General');
658 foreach ($files as $file) {
659 $template_id = attr($file['id']);
660 $this_cat = attr($file['category']);
661 $title = $category_list[$file['category']]['title'] ?: $cat;
662 $this_name = attr($file['template_name']);
663 $events = $templateService->fetchTemplateEvent($profile, $template_id);
664 $recurring = attr($events['recurring'] ?? '');
665 $trigger = attr($events['event_trigger'] ?? ''); // max 32 char
666 $notify_trigger = attr($events['notify_trigger'] ?? ''); // max 32 char
667 $days = attr($events['period'] ?? '');
668 $notify_days = attr($events['notify_period'] ?? '');
669 if ($file['mime'] === 'application/pdf') {
670 continue;
673 <li class='list-group-item bg-warning text-light px-1 py-1 mb-1' data-id="<?php echo $template_id; ?>" data-name="<?php echo $this_name; ?>" data-category="<?php echo $this_cat; ?>">
674 <span class="p-1 font-weight-bold"><?php echo text($file['template_name']) . ' ' . xlt('in category') . ' ' . text($title); ?></span>
675 <!-- Notice! The notify event input is patched out until I get around to it. -->
676 <form class='form form-inline bg-light text-dark py-1 pl-1'>
677 <div class='input-group-sm input-group-prepend d-none'>
678 <label class="form-check-inline"><?php echo xlt('OneTime') ?>
679 <input name="onetimeIsOkay" type='checkbox' class="input-control-sm ml-1 mt-1" title="<?php echo xla('Enable Auto Portal log in for presenting document to patient.') ?>" />
680 </label>
681 </div>
682 <label class='font-weight-bold mr-1 d-none'><?php echo xlt('Notify') ?></label>
683 <div class='input-group-sm input-group-prepend d-none'>
684 <input name="notify_days" type="text" style="width: 50px;" class='input-control-sm ml-1' placeholder="<?php echo xla('days') ?>" value="<?php echo $notify_days ?>" />
685 <label class="mx-1"><?php echo xlt('Days') ?></label>
686 </div>
687 <div class='input-group-sm input-group-prepend d-none'>
688 <select name="notify_when" class='input-control-sm mx-1'>
689 <option value=""><?php echo xlt('Unassigned'); ?></option>
690 <option <?php echo $notify_trigger === 'new' ? 'selected' : ''; ?> value="new"><?php echo xlt('New'); ?></option>
691 <option <?php echo $notify_trigger === 'before_appointment' ? 'selected' : ''; ?> value='before_appointment'><?php echo xlt('Before Appointment'); ?></option>
692 <option <?php echo $notify_trigger === 'after_appointment' ? 'selected' : ''; ?> value='after_appointment'><?php echo xlt('After Appointment'); ?></option>
693 <option <?php echo $notify_trigger === 'before_expires' ? 'selected' : ''; ?> value="before_expires"><?php echo xlt('Before Expires'); ?></option>
694 <option <?php echo $notify_trigger === 'in_edit' ? 'selected' : ''; ?> value="in_edit"><?php echo xlt('In Edit'); ?></option>
695 </select>
696 </div>
697 <div class='input-group-sm input-group-prepend'>
698 <label class="form-check-inline"><?php echo xlt('Recurring') ?>
699 <input <?php echo $recurring ? 'checked' : '' ?> name="recurring" type='checkbox' class="input-control-sm ml-1 mt-1" />
700 </label>
701 </div>
702 <div class='input-group-sm input-group-prepend'>
703 <label><?php echo xlt('On') ?></label>
704 <select name="when" class='input-control-sm mx-1'>
705 <!--<option value=""><?php /*echo xlt('Unassigned') */ ?></option>-->
706 <option <?php echo $trigger === 'completed' ? 'selected' : ''; ?> value="completed"><?php echo xlt('Completed') ?></option>
707 <option <?php echo $trigger === 'always' ? 'selected' : ''; ?> value='always'><?php echo xlt('Always') ?></option>
708 <option <?php echo $trigger === 'once' ? 'selected' : ''; ?> value='once'><?php echo xlt('One time') ?></option>
709 <option <?php echo $trigger === '30:90:365' ? 'selected' : ''; ?> value='30:90:365'><?php echo xlt('30-90-365') ?></option>
710 </select>
711 </div>
712 <div class='input-group-sm input-group-prepend'>
713 <label><?php echo xlt('Every') ?></label>
714 <input name="days" type="text" style="width: 50px;" class='input-control-sm ml-1' placeholder="<?php echo xla('days') ?>" value="<?php echo $days ?>" />
715 <label class="mx-1" for="<?php echo $profile_esc ?>-days"><?php echo xlt('Days') ?></label>
716 </div>
717 </form>
718 </li>
719 <?php
722 echo "</ul>\n";
725 </div>
726 </div>
727 </div>
728 </div>
729 <hr />
730 </body>
731 </html>
732 <?php }