Add title to all appointment sql queries (#7311)
[openemr.git] / portal / messaging / messages.php
blob0878acf0ac7c731c0a40b0d66856d09b5c3e5156
1 <?php
3 /**
4 * messages.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 * @author Tyler Wrenn <tyler@tylerwrenn.com>
11 * @copyright Copyright (c) 2016-2021 Jerry Padgett <sjpadgett@gmail.com>
12 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
13 * @copyright Copyright (c) 2020 Tyler Wrenn <tyler@tylerwrenn.com>
14 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
17 // Will start the (patient) portal OpenEMR session/cookie.
18 require_once(__DIR__ . "/../../src/Common/Session/SessionUtil.php");
19 OpenEMR\Common\Session\SessionUtil::portalSessionStart();
21 if (isset($_SESSION['pid']) && isset($_SESSION['patient_portal_onsite_two'])) {
22 $pid = $_SESSION['pid'];
23 $ignoreAuth_onsite_portal = true;
24 require_once(__DIR__ . "/../../interface/globals.php");
25 define('IS_DASHBOARD', false);
26 define('IS_PORTAL', $_SESSION['portal_username']);
27 } else {
28 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
29 $ignoreAuth = false;
30 require_once(__DIR__ . "/../../interface/globals.php");
31 if (!isset($_SESSION['authUserID'])) {
32 $landingpage = "index.php";
33 header('Location: ' . $landingpage);
34 exit();
37 define('IS_DASHBOARD', $_SESSION['authUser']);
38 define('IS_PORTAL', false);
41 require_once("$srcdir/patient.inc.php");
42 require_once("$srcdir/options.inc.php");
43 require_once("$srcdir/classes/Document.class.php");
44 require_once("./../lib/portal_mail.inc.php");
46 use OpenEMR\Common\Csrf\CsrfUtils;
47 use OpenEMR\Core\Header;
48 use OpenEMR\Events\Messaging\SendSmsEvent;
50 if (!(isset($GLOBALS['portal_onsite_two_enable'])) || !($GLOBALS['portal_onsite_two_enable'])) {
51 echo xlt('Patient Portal is turned off');
52 exit;
55 $docid = empty($_REQUEST['docid']) ? 0 : (int)$_REQUEST['docid'];
56 $orderid = empty($_REQUEST['orderid']) ? 0 : (int)$_REQUEST['orderid'];
58 $result = getMails(IS_DASHBOARD ?: IS_PORTAL, 'inbox', '', '');
59 $theresult = array();
60 foreach ($result as $iter) {
61 $theresult[] = $iter;
64 $dashuser = array();
65 if (IS_DASHBOARD) {
66 $dashuser = getUserIDInfo($_SESSION['authUserID']);
69 function getAuthPortalUsers()
71 $resultpd = $resultusers = $resultpatients = array();
73 if (IS_DASHBOARD) { // admin can mail anyone
74 $authusers = sqlStatement("SELECT users.username as userid,
75 CONCAT(users.fname,' ',users.lname) as username, 'user' as type FROM users WHERE active = 1 AND portal_user = 1");
76 while ($row = sqlFetchArray($authusers)) {
77 $resultusers[] = $row;
79 if (count($resultusers ?? []) === 0) {
80 $resultusers[] = sqlQuery("SELECT users.username as userid,
81 CONCAT(users.fname,' ',users.lname) as username, 'user' as type FROM users WHERE id = 1");
84 $authpatients = sqlStatement("SELECT (CONCAT(patient_data.fname, patient_data.id)) as userid,
85 CONCAT(patient_data.fname,' ',patient_data.lname) as username,'p' as type,patient_data.pid as pid FROM patient_data WHERE allow_patient_portal = 'YES'");
86 while ($row = sqlFetchArray($authpatients)) {
87 $resultpatients[] = $row;
90 $resultpd = array_merge($resultusers, $resultpatients);
91 } else { // patient gets only portal users
92 $resultpd = array();
93 $authusers = sqlStatement("SELECT users.username as userid, CONCAT(users.fname,' ',users.lname) as username FROM users WHERE active = 1 AND portal_user = 1");
94 while ($row = sqlFetchArray($authusers)) {
95 $resultpd[] = $row;
97 if (count($resultpd ?? []) === 0) {
98 $resultpd[] = sqlQuery("SELECT users.username as userid, CONCAT(users.fname,' ',users.lname) as username FROM users WHERE id = 1");
102 return $resultpd;
106 <!DOCTYPE html>
107 <html lang="en">
108 <head>
109 <meta charset="utf-8" />
110 <?php
111 if (IS_PORTAL) {
112 Header::setupHeader(['no_main-theme', 'portal-theme', 'summernote', 'angular', 'angular-summernote', 'angular-sanitize', 'checklist-model', 'dompurify']);
113 } else {
114 Header::setupHeader(['summernote', 'angular', 'angular-summernote', 'angular-sanitize', 'checklist-model', 'dompurify']);
117 <title><?php echo xlt("Secure Messaging"); ?></title>
118 <meta name="description" content="Mail Application" />
119 </head>
120 <body class="body_top">
121 <script>
122 (function () {
123 var app = angular.module("emrMessageApp", ['ngSanitize', 'summernote', "checklist-model"]);
124 app.controller('inboxCtrl', ['$scope', '$filter', '$http', '$window', '$q', function ($scope, $filter, $http, $window, $q) {
125 $scope.date = new Date;
126 $scope.sortingOrder = 'id';
127 $scope.pageSizes = [5, 10, 20, 50, 100];
128 $scope.reverse = false;
129 $scope.filteredItems = [];
130 $scope.groupedItems = [];
131 $scope.itemsPerPage = 20;
132 $scope.pagedItems = [];
133 $scope.compose = [];
134 $scope.selrecip = [];
135 $scope.currentPage = 0;
136 $scope.sentItems = [];
137 $scope.allItems = [];
138 $scope.deletedItems = [];
139 $scope.inboxItems = [];
140 $scope.inboxItems = <?php echo json_encode($theresult);?>;
141 $scope.userproper = <?php echo !empty($_SESSION['ptName']) ? js_escape($_SESSION['ptName']) : js_escape($dashuser['fname'] . ' ' . $dashuser['lname']);?>;
142 $scope.isPortal = "<?php echo IS_PORTAL;?>";
143 $scope.isDashboard = "<?php echo IS_DASHBOARD ?: 0;?>";
144 $scope.cUserId = $scope.isPortal ? $scope.isPortal : $scope.isDashboard;
145 $scope.authrecips = <?php echo json_encode(getAuthPortalUsers());?>;
146 $scope.compose.task = 'add';
147 $scope.xLate = [];
148 $scope.xLate.confirm = [];
149 $scope.xLate.fwd = <?php echo xlj('Forwarded Portal Message Re: '); ?>;
150 $scope.xLate.confirm.one = <?php echo xlj('Confirm to Archive Current Thread?'); ?>;
151 $scope.xLate.confirm.all = <?php echo xlj('Confirm to Archive Selected Messages?'); ?>;
152 $scope.xLate.confirm.err = <?php echo xlj('You are sending to yourself!'); ?>; // I think I got rid of this ability - look into..
153 $scope.csrf = <?php echo js_escape(CsrfUtils::collectCsrfToken('messages-portal')); ?>;
154 $scope.isInit = false;
156 $scope.init = function () {
157 $http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
158 let promises = [];
159 promises.push($scope.getSentMessages());
160 promises.push($scope.getAllMessages());
161 promises.push($scope.getDeletedMessages());
162 $scope.isInboxSelected();
163 $scope.search();
164 $scope.errorLoadingMessages = false;
165 $q.all(promises)
166 .then(() => {
167 $scope.isInit = true;
169 .catch(error => {
170 $scope.errorLoadingMessages = true;
171 $scope.isInit = true;
175 const searchMatch = function (haystack, needle) {
176 if (!needle) {
177 return true;
179 return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
182 // filter the items
183 $scope.search = function () {
184 $scope.filteredItems = $filter('filter')($scope.items, function (item) {
185 for (var attr in item) {
186 if (searchMatch(item[attr], $scope.query))
187 return true;
189 return false;
191 $scope.currentPage = 0;
192 // now group by pages
193 $scope.groupToPages();
196 // calculate page in place
197 $scope.groupToPages = function () {
198 $scope.selected = null;
199 $scope.pagedItems = [];
200 for (let i = 0; i < $scope.filteredItems.length; i++) {
201 if (i % $scope.itemsPerPage === 0) {
202 $scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [$scope.filteredItems[i]];
203 } else {
204 $scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
209 $scope.range = function (start, end) {
210 const ret = [];
211 if (!end) {
212 end = start;
213 start = 0;
215 for (var i = start; i < end; i++) {
216 ret.push(i);
218 return ret;
221 $scope.prevPage = function () {
222 if ($scope.currentPage > 0) {
223 $scope.currentPage--;
225 return false;
228 $scope.nextPage = function () {
229 if ($scope.currentPage < $scope.pagedItems.length - 1) {
230 $scope.currentPage++;
232 return false;
235 $scope.setPage = function () {
236 $scope.currentPage = this.n;
239 $scope.deleteItem = function (idx) {
240 if (!confirm($scope.xLate.confirm.one)) return false;
241 const itemToDelete = $scope.allItems[idx];
242 const idxInItems = $scope.items.indexOf(itemToDelete);
243 $scope.deleteMessage(itemToDelete.mail_chain); // Just this user's message
244 $scope.items.splice(idxInItems, 1);
245 $scope.search();
246 $scope.init()
247 return false;
250 $scope.batchDelete = function (i) {
251 if (!confirm($scope.xLate.confirm.all)) return false;
252 var itemToDelete = [];
253 angular.forEach(i, function (o, key) {
254 if (o.hasOwnProperty('deleted')) {
255 itemToDelete.push($scope.items[i.indexOf(o)].id);
258 $http.post('handle_note.php', $.param({'task': 'massdelete', 'notejson': JSON.stringify(itemToDelete), 'csrf_token_form': $scope.csrf})).then(function successCallback(response) {
259 $window.location.reload();
260 }, function errorCallback(response) {
261 alert(response.data);
263 return false;
266 $scope.deleteMessage = function (id) {
267 $http.post('handle_note.php', $.param({'task': 'delete', 'noteid': id, 'csrf_token_form': $scope.csrf})).then(function successCallback(response) {
268 return true;
269 }, function errorCallback(response) {
270 alert(response.data);
275 $scope.isMessageSelected = function () {
276 return typeof $scope.selected !== "undefined" && $scope.selected !== null;
279 $scope.isSentSelected = function () {
280 $scope.isSent = true;
281 $scope.isTrash = $scope.isAll = $scope.isInbox = false;
282 $scope.items = [];
283 $scope.items = $scope.sentItems;
284 $scope.search();
285 return true;
288 $scope.isTrashSelected = function () {
289 $scope.isTrash = true;
290 $scope.isSent = $scope.isAll = $scope.isInbox = false;
291 $scope.items = [];
292 $scope.items = $scope.deletedItems;
293 $scope.search();
294 return true;
297 $scope.isInboxSelected = function () {
298 $scope.isInbox = true;
299 $scope.isTrash = $scope.isAll = $scope.isSent = false;
300 $scope.items = $scope.inboxItems;
301 $scope.search();
302 return true;
305 $scope.isAllSelected = function () {
306 $scope.isAll = true;
307 $scope.isTrash = $scope.isSent = $scope.isInbox = false;
308 $scope.items = $scope.allItems;
309 $scope.search();
310 return true;
313 $scope.readMessage = function (idx) {
314 if ($scope.items[idx].message_status == 'New') { // mark mail read else ignore
315 $http.post('handle_note.php', $.param({'task': 'setread', 'noteid': $scope.items[idx].id, 'csrf_token_form': $scope.csrf})).then(function successCallback(response) {
316 $scope.items[idx].message_status = 'Read';
317 $scope.selected.message_status = 'Read';
318 }, function errorCallback(response) {
319 alert(response.data);
322 idx = $filter('getById')($scope.allItems, this.item.id);
323 $scope.isAll = true;
324 $scope.isTrash = $scope.isSent = $scope.isInbox = false;
325 $scope.items = $scope.allItems;
326 $scope.selected = $scope.items[idx];
329 $scope.selMessage = function (idx) {
330 $scope.selected = $scope.allItems[idx];
334 $scope.readAll = function () {
335 for (var i in $scope.items) {
336 $scope.items[i].message_status = 'Read';
340 $scope.closeMessage = function () {
341 $scope.selected = null;
344 $scope.renderMessageBody = function (html) {
345 html = DOMPurify.sanitize(html, { USE_PROFILES: { html: true } });
346 return html;
349 $scope.htmlToText = function (html) {
350 const hold = document.createElement('DIV');
351 hold.innerHTML = DOMPurify.sanitize(html, { USE_PROFILES: { html: true } });
352 return jsText(hold.textContent || hold.innerText || '');
355 // note backend supports a task of getinbox but we prefetch this on server so we don't have that here.
356 $scope.getAllMessages = function () {
357 return $http.post('handle_note.php', $.param({'task': 'getall', 'csrf_token_form': $scope.csrf})).then(function successCallback(response) {
358 if (response.data) {
359 $scope.allItems = angular.copy(response.data);
360 } else alert(response.data);
361 }, function errorCallback(response) {
362 alert(response.data);
366 $scope.getDeletedMessages = function () {
367 return $http.post('handle_note.php', $.param({'task': 'getdeleted', 'csrf_token_form': $scope.csrf})).then(function successCallback(response) {
368 if (response.data) {
369 $scope.deletedItems = [];
370 $scope.deletedItems = angular.copy(response.data);
371 } else alert(response.data);
372 }, function errorCallback(response) {
373 alert(response.data);
377 $scope.getSentMessages = function () {
378 return $http.post('handle_note.php', $.param({'task': 'getsent', 'csrf_token_form': $scope.csrf})).then(function successCallback(response) {
379 $scope.sentItems = [];
380 $scope.sentItems = angular.copy(response.data);
381 }, function errorCallback(response) {
382 alert(response.data);
386 $scope.submitForm = function (compose) {
387 $http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
388 // re-enable title for submit
389 $("#title").prop("disabled", false);
390 $("#selSendto").prop("disabled", false);
392 compose.csrf_token_form = $scope.csrf;
393 compose.sender_id = $scope.cUserId;
394 compose.sender_name = $scope.userproper;
395 if ($scope.selrecip == $scope.cUserId) {
396 if (!confirm($scope.xLate.confirm.err))
397 return false;
399 if (compose.task == 'add') {
400 compose.recipient_name = $("#selSendto option:selected").text();
402 if (compose.task == 'forward') { // Just overwrite default reply but send to pnotes.
403 compose.sender_id = $("#selForwardto option:selected").val();
404 compose.sender_name = $("#selForwardto option:selected").text();
405 compose.selrecip = compose.recipient_id;
406 } else {
407 compose.inputBody = $("#inputBody").summernote('code');
409 return true; // okay to submit
412 $('#modalCompose').on('hidden.bs.modal', function (e) {
413 window.location.reload();
416 $('#modalCompose').on('show.bs.modal', function (e) {
417 // Sets up the compose modal before we show it
418 $scope.compose = [];
419 $('#inputBody').summernote('destroy');
420 var mode = $(e.relatedTarget).attr('data-mode');
421 $scope.compose.task = mode;
422 if (mode == 'forward') {
423 $('#modalCompose .modal-header .modal-title').html("Forward Message");
424 $scope.compose.task = mode;
425 var recipId = $(e.relatedTarget).attr('data-whoto');
426 var title = $(e.relatedTarget).attr('data-mtitle');
427 var uname = $(e.relatedTarget).attr('data-username');
428 $(e.currentTarget).find('select[id="selSendto"]').prop("disabled", false);
429 $(e.currentTarget).find('input[name="title"]').prop("disabled", false);
430 $scope.compose.title = title;
431 $scope.compose.selrecip = recipId;
432 $scope.compose.selrecip.username = uname;
433 $scope.compose.recipient_name = uname;
434 $scope.compose.recipient_id = recipId;
435 angular.forEach($scope.authrecips, function (o, key) {// Need the pid of patient for pnotes.
436 if (o.userid == recipId) {
437 $scope.compose.pid = o.pid;
440 const fmsg = '\n\n\n> ' + $scope.xLate.fwd + title + ' by ' + uname + '\n> ' + $("#referMsg").text();
441 $("textarea#finputBody").text(fmsg)
442 $scope.compose.noteid = $(e.relatedTarget).attr('data-noteid');
443 } else if (mode == 'reply') {
444 $('#inputBody').summernote({
445 focus: true,
446 height: '225px',
447 width: '100%',
448 tabsize: 4,
449 disableDragAndDrop: true,
450 dialogsInBody: true,
451 dialogsFade: true
453 $('#modalCompose .modal-header .modal-title').html(<?php xlt("Compose Reply Message"); ?>)
454 $scope.compose.task = mode;
455 //get data attributes of the clicked element (selected recipient) for replies only
456 var chain = $(e.relatedTarget).attr('data-mailchain');
457 if (chain == '0') {
458 chain = $(e.relatedTarget).attr('data-noteid');
460 let recipId = $(e.relatedTarget).attr('data-whoto');
461 let title = $(e.relatedTarget).attr('data-mtitle');
462 let uname = $(e.relatedTarget).attr('data-username');
463 $(e.currentTarget).find('select[id="selSendto"]').val(recipId)
464 $(e.currentTarget).find('input[name="title"]').val(title);
465 // Set the modal var's
466 $scope.compose.title = title;
467 $scope.compose.selrecip = recipId;
468 $scope.compose.selrecip.username = uname;
469 $scope.compose.recipient_name = uname;
470 $scope.compose.recipient_id = recipId;
471 $scope.compose.noteid = chain;
472 } else {
473 $('#inputBody').summernote({
474 width: '100%',
475 focus: true,
476 height: '375px',
477 tabsize: 4,
478 disableDragAndDrop: true,
479 dialogsInBody: true,
480 dialogsFade: true,
481 popover: {
482 image: [],
483 link: [],
484 air: []
487 $('#modalCompose .modal-header .modal-title').html(<?php xlt("Compose New Message"); ?>)
488 $scope.compose.task = 'add';
489 $(e.currentTarget).find('select[id="selSendto"]').prop("disabled", false);
490 $(e.currentTarget).find('input[name="title"]').prop("disabled", false);
492 if ($scope.compose.task != 'reply') {
493 $scope.$apply();
495 }); // on modal
496 // initialize application
497 if (!$scope.isInit) {
498 $scope.init();
500 }]) /* end inbox functions */
501 .filter('Chained', function () {
502 return function (input, id) {
503 var output = [];
504 if (isNaN(id)) {
505 output = input;
506 } else {
507 angular.forEach(input, function (item) {
508 if (item.mail_chain == id) {
509 output.push(item)
513 return output;
515 }).filter('getById', function () {
516 return function (input, id) {
517 var i = 0, len = input.length;
518 for (; i < len; i++) {
519 if (+input[i].id == +id) {
520 return i;
523 return null;
525 }).controller('messageCtrl', ['$scope', function ($scope) {
526 $scope.message = function (idx) {
527 return items(idx);
529 }]); // end messageCtrl
530 })(); // application end
532 <?php
533 if (IS_DASHBOARD) {
534 $GLOBALS['kernel']->getEventDispatcher()->dispatch(new SendSmsEvent($pid), SendSmsEvent::JAVASCRIPT_READY_SMS_POST);
537 </script>
538 <ng ng-app="emrMessageApp">
539 <div class="container-fluid" id='main' ng-controller="inboxCtrl">
540 <div class='my-3'>
541 <h2><i class='fa fa-envelope w-auto h-auto mr-2'></i><?php echo xlt('Secure Messaging'); ?></h2>
542 </div>
543 <div class="row" ng-class="{'d-none': isInit}">
544 <div class="col-12">
545 <div class="alert alert-info"><h3><?php echo xlt("Loading..."); ?> <i class="wait fa fa-cog fa-spin ml-2"></i></h3></div>
546 </div>
547 </div>
548 <div class="row d-none" ng-class="{'d-none': !isInit}">
549 <div class="col-md-2 p-0 m-0 text-left border-right bg-light text-dark">
550 <div class="sticky-top">
551 <ul class="nav nav-pills nav-stacked flex-column">
552 <li class="nav-item">
553 <a class="nav-link active" data-toggle="pill" href="javascript:;" ng-click="isInboxSelected()"><span class="badge float-right">{{inboxItems.length}}</span><?php echo xlt('Inbox'); ?></a>
554 </li>
555 <li class="nav-item">
556 <a class="nav-link" data-toggle="pill" href="javascript:;" ng-click="isSentSelected()"><span class="badge float-right">{{sentItems.length}}</span><?php echo xlt('Sent{{Mails}}'); ?></a>
557 </li>
558 <li class="nav-item">
559 <a class="nav-link" data-toggle="pill" href="javascript:;" ng-click="isAllSelected()"><span class="badge float-right">{{allItems.length}}</span><?php echo xlt('All{{Mails}}'); ?></a>
560 </li>
561 <li class="nav-item">
562 <a class="nav-link" data-toggle="pill" href="javascript:;" ng-click="isTrashSelected()"><span class="badge float-right">{{deletedItems.length}}</span><?php echo xlt('Archive'); ?></a>
563 </li>
564 <li class="nav-item">
565 <a class="nav-link" href="<?php echo $GLOBALS['web_root'] ?>/portal/patient/provider" ng-show="!isPortal"><?php echo xlt('Exit Mail'); ?></a>
566 </li>
567 <!--<li class="nav-item">
568 <a class="nav-link" href="javascript:;" onclick='window.location.replace("<?php /*echo $GLOBALS['web_root'] */ ?>/portal/home.php")' ng-show="isPortal"><?php /*echo xlt('Exit'); */ ?></a>
569 </li>-->
570 </ul>
571 </div>
572 </div>
573 <div class="col-md-10">
574 <!--inbox toolbar-->
575 <div class="row" ng-show="!isMessageSelected()">
576 <div class="col-12 mb-2">
577 <button class="btn btn-primary" title="<?php echo xla("Compose Message"); ?>" data-mode="add" data-toggle="modal" data-target="#modalCompose">
578 <span class="fa fa-edit fa-lg"></span> <?php echo xlt("Compose Message"); ?>
579 </button>
580 <?php
581 if (IS_DASHBOARD) {
582 $GLOBALS['kernel']->getEventDispatcher()->dispatch(new SendSmsEvent($_SESSION['pid'] ?? 0), SendSmsEvent::ACTIONS_RENDER_SMS_POST);
585 <a class="btn btn-secondary" data-toggle="tooltip" title="<?php echo xla("Refresh to see new messages"); ?>" id="refreshInbox" href="javascript:;" onclick='window.location.replace("./messages.php")'> <span class="fa fa-sync fa-lg"></span>
586 </a>
587 <div class="btn-group btn-group float-right">
588 <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown"><?php echo xlt('Actions'); ?></button>
589 <ul class="dropdown-menu dropdown-menu-right">
590 <li>
591 <a class="dropdown-item" href="javascript:;" ng-click="readAll()"><?php echo xlt('Mark all as read'); ?></a>
592 </li>
593 <li class="dropdown-divider"></li>
594 <li>
595 <a class="dropdown-item" href="" data-mode="add" data-toggle="modal" data-target="#modalCompose"><i class="fa fa-edit"></i> <?php echo xlt('Compose Message'); ?></a>
596 </li>
597 <li ng-show='!isTrash'>
598 <a class="dropdown-item" href="javascript:;" ng-click="batchDelete(items)"><i class="fa fa-trash"></i> <?php echo xlt('Send Selected to Archive'); ?></a></li>
599 <li>
600 <a href="javascript:;" onclick='window.location.replace("./messages.php")' ng-show="isPortal" class="dropdown-item"><i class="fa fa-sync"></i> <?php echo xlt('Refresh'); ?></a>
601 </li>
602 <li>
603 <a href="<?php echo $GLOBALS['web_root'] ?>/portal/patient/provider" ng-show="!isPortal" class="dropdown-item"><i class="fa fa-home"></i> <?php echo xlt('Return Home'); ?></a>
604 </li>
605 </ul>
606 </div>
607 </div>
608 <!--/col-->
609 <div class="col-12"></div>
610 </div>
611 <!--/row-->
612 <!--/inbox toolbar-->
613 <div class="inbox" id="inboxPanel">
614 <!--message list-->
615 <div class="table-responsive" ng-show="!isMessageSelected()">
616 <table class="table table-striped table-bordered table-hover refresh-container pull-down">
617 <thead class="bg-info d-none"></thead>
618 <tbody>
619 <tr ng-repeat="item in pagedItems[currentPage]" role='button'>
620 <!-- | orderBy:sortingOrder:reverse -->
621 <td role = "button" class="message-row">
622 <span class="col-sm-1" style="max-width: 5px;"><input type="checkbox" checklist-model="item.deleted" value={{item.deleted}}></span>
624 <span class="col-sm-1 px-1" ng-click="readMessage($index)" ><span ng-class="{strong: !item.read}">{{item.message_status}}</span></span>
625 <span class="col-sm-2 px-1" ng-click="readMessage($index)" ><span ng-class="{strong: !item.read}">{{item.date | date:'yyyy-MM-dd hh:mm'}}</span></span>
626 <span class="col-sm-3 px-1" ng-click="readMessage($index)" >
627 <a ng-click="readMessage($index)" class="btn-link">
628 <span ng-class="{strong: !item.read}">{{item.sender_name}} to {{item.recipient_name}}</span>
629 </a>
630 </span>
631 <span class="col-sm-1" ng-click="readMessage($index)">
632 <a ng-click="readMessage($index)" class="btn-link">
633 <span ng-class="{strong: !item.read}">{{item.title}}</span>
634 </a>
635 </span>
636 <span class="col-sm-4 px-1" ng-click="readMessage($index)"><span ng-class="{strong: !item.read}" ng-bind='(htmlToText(item.body) | limitTo:35)'></span></span>
637 <!-- below for attachments, eventually -->
638 <!-- <span class="col-sm-1 " ng-click="readMessage($index)"><span ng-show="item.attachment"
639 class="glyphicon glyphicon-paperclip float-right"></span> <span ng-show="item.priority==1"
640 class="float-right glyphicon glyphicon-warning-sign text-danger"></span></span> -->
641 </td>
642 </tr>
643 </tbody>
644 </table>
645 </div>
646 <!--message detail-->
647 <div class="container-fluid" ng-show="isMessageSelected()">
648 <div class="row" ng-controller="messageCtrl">
649 <div class="w-100 pl-1 mb-1 bg-light text-dark">
650 <h5 class="pt-2">
651 <a href="javascript:;" ng-click="groupToPages()"><?php echo xlt('Conversation from'); ?></a>
652 <strong>{{selected.sender_name}}</strong> <?php echo xlt('regarding'); ?> <strong>{{selected.title}}</strong> <?php echo xlt('on'); ?> &lt;{{selected.date | date:'yyyy-MM-dd hh:mm'}}&gt;
653 </h5>
654 <!-- Leave below for future menu items -->
655 <!--<span class="btn-group float-right">
656 <button ng-show="selected.sender_id != cUserId" class="btn btn-primary" title="<?php /*echo xla('Reply to this message'); */?>" data-toggle="modal" data-mode="reply" data-noteid='{{selected.id}}' data-whoto='{{selected.sender_id}}' data-mtitle='{{selected.title}}' data-username='{{selected.sender_name}}' data-mailchain='{{selected.mail_chain}}' data-target="#modalCompose">
657 <i class="fa fa-reply"></i> <?php /*echo xlt('Reply'); */?></button>
658 <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown" title="<?php /*echo xla("More options"); */?>"></button>
659 <ul class="dropdown-menu float-right">
660 <li ng-show='!isTrash'><a href="javascript:;" ng-click="batchDelete(items)"><i class="fa fa-trash"></i> <?php /*echo xlt('Send to Archive'); */?></a></li>
661 </ul>
662 <button ng-show='!isTrash' class="btn btn-md btn-primary float-right" ng-click="deleteItem(items.indexOf(selected))" title="<?php /*echo xla('Delete this message'); */?>" data-toggle="tooltip">
663 <i class="fa fa-trash fa-1x"></i>
664 </button>
665 </span>-->
666 </div>
667 <div class="table-responsive row ml-1">
668 <table class="table table-hover table-striped table-bordered refresh-container pull-down">
669 <thead><?php echo xlt('Associated Messages in thread.');?></thead>
670 <tbody>
671 <tr class="animate-repeat" ng-repeat="item in allItems | Chained:selected.mail_chain">
672 <td role = "button" ng-click="readMessage($index)">
673 <span class="col-sm px-1"><span>{{item.date | date:'yyyy-MM-dd hh:mm'}}</span></span>
674 <span class="col-sm"><span>{{item.message_status}}</span></span>
675 <span class="col-sm px-1"><span>{{item.sender_name}}
676 to {{item.recipient_name}}</span></span> <span class="col-sm-1"><span>{{item.title}}</span></span>
677 <span class="col-sm px-1" ng-hide="selected.id == item.id"><span ng-bind-html='(htmlToText(item.body) | limitTo:35)'></span></span>
678 <span class='btn-group float-right m-0'>
679 <button ng-show="selected.sender_id != cUserId && selected.id == item.id" class="btn btn-primary btn-small" title="<?php echo xla('Reply to this message'); ?>" data-toggle="modal" data-mode="reply" data-noteid='{{selected.id}}' data-whoto='{{selected.sender_id}}' data-mtitle='{{selected.title}}' data-username='{{selected.sender_name}}' data-mailchain='{{selected.mail_chain}}' data-target="#modalCompose"><i class="fa fa-reply"></i></button>
680 <button ng-show="selected.id == item.id && selected.sender_id != cUserId && !isPortal" class="btn btn-primary btn-small" title="<?php echo xla('Forward message to practice.'); ?>" data-toggle="modal" data-mode="forward" data-noteid='{{selected.id}}' data-whoto='{{selected.sender_id}}' data-mtitle='{{selected.title}}' data-username='{{selected.sender_name}}' data-mailchain='{{selected.mail_chain}}' data-target="#modalCompose"><i class="fa fa-share"></i></button>
681 <button ng-show='!isTrash && selected.id == item.id' class="btn btn-small btn-primary" ng-click="deleteItem(items.indexOf(selected))" title="<?php echo xla('Archive this message'); ?>" data-toggle="tooltip"><i class="fa fa-trash fa-1x"></i>
682 </button>
683 </span>
684 <div class='col jumbotron jumbotron-fluid my-3 p-1 bg-light text-dark rounded border border-info' ng-show="selected.id == item.id">
685 <span ng-bind-html=renderMessageBody(selected.body)></span>
686 </div>
687 </td>
688 </tr>
689 </tbody>
690 </table>
691 </div>
692 <!--/message body-->
693 </div>
694 <!--/row-->
695 </div>
696 </div>
697 <!--/inbox panel-->
698 <!--paging-->
699 <div class="float-right my-2" ng-hide="selected">
700 <span class="text-muted"><strong>{{(itemsPerPage * currentPage) + 1}}</strong>~<strong>{{(itemsPerPage
701 * currentPage) + pagedItems[currentPage].length}}</strong> of <strong>{{items.length}}</strong></span>
702 <div class="btn-group" ng-show="items.length > itemsPerPage">
703 <button type="button" class="btn btn-secondary btn-lg" ng-class="{disabled: currentPage == 0}" ng-click="prevPage()"><i class="fa fa-chevron-left"></i></button>
704 <button type="button" class="btn btn-secondary btn-lg" ng-class="{disabled: currentPage == pagedItems.length - 1}" ng-click="nextPage()"><i class="fa fa-chevron-right"></i></button>
705 </div>
706 </div>
707 </div>
708 <!-- /.modal compose message -->
709 <div class="modal fade" id="modalCompose">
710 <div class="modal-dialog modal-xl">
711 <div class="modal-content">
712 <div class="modal-header">
713 <h4 class="modal-title"><?php echo xlt('Compose Message'); ?></h4>
714 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
715 </div>
716 <div class="modal-body ">
717 <div class="col-12">
718 <label ng-show='selected.mail_chain'><?php echo xlt('Refer to Message') . ' # '; ?>{{selected.id}}</label>
719 <div class="jumbotron col-lg-12 m-1 p-1 bg-light text-dark" id="referMsg" ng-show='selected.mail_chain' ng-bind-html='renderMessageBody(selected.body)'></div>
721 <form role="form" class="form-horizontal" ng-submit="submitForm(compose)" name="fcompose" id="fcompose" method="post" action="./handle_note.php">
722 <fieldset class="row">
723 <div class="col-lg-6 input-group my-2">
724 <label for="selSendto"><?php echo xlt('To{{Destination}}'); ?></label>
725 <select class="form-control ml-2 to-select-forward" id="selForwardto" ng-hide="compose.task != 'forward'" ng-model="compose.selrecip" ng-options="recip.userid as recip.username for recip in authrecips | filter:'user' track by recip.userid"></select>
726 <select class="form-control ml-2 to-select-send" id="selSendto" ng-hide="compose.task == 'forward'" ng-model="compose.selrecip" ng-options="recip.userid as recip.username for recip in authrecips track by recip.userid"></select>
727 </div>
728 <div class="input-group col-lg-6 my-2">
729 <label for="title"><?php echo xlt('Subject'); ?></label>
730 <input type='text' list='listid' name='title' id='title' class="form-control ml-2" ng-model='compose.title' value="<?php echo xla('General'); ?>">
731 <datalist id='listid'>
732 <option label='<?php echo xlt('General'); ?>'
733 value='<?php echo xla('General'); ?>'></option>
734 <option label='<?php echo xlt('Insurance'); ?>'
735 value='<?php echo xla('Insurance'); ?>'></option>
736 <option label='<?php echo xlt('Prior Auth'); ?>'
737 value='<?php echo xla('Prior Auth'); ?>'></option>
738 <option label='<?php echo xlt('Bill/Collect'); ?>'
739 value='<?php echo xla('Bill/Collect'); ?>'></option>
740 <option label='<?php echo xlt('Referral'); ?>'
741 value='<?php echo xla('Referral'); ?>'></option>
742 <option label='<?php echo xlt('Pharmacy'); ?>'
743 value='<?php echo xla('Pharmacy'); ?>'></option>
744 </datalist>
745 </div>
746 <div class="col-12" id="inputBody" ng-hide="compose.task == 'forward'" ng-model="compose.inputBody"></div>
747 <textarea class="col-12" id="finputBody" rows="8" ng-hide="compose.task != 'forward'" ng-model="compose.inputBody"></textarea>
748 </fieldset>
749 <input type="hidden" name="csrf_token_form" id="csrf_token_form" ng-value="compose.csrf_token_form" />
750 <input type='hidden' name='noteid' id='noteid' ng-value="compose.noteid" />
751 <input type='hidden' name='replyid' id='replyid' ng-value='selected.reply_mail_chain' />
752 <input type='hidden' name='recipient_id' ng-value='compose.selrecip' />
753 <input type='hidden' name='recipient_name' ng-value='compose.recipient_name' />
754 <input type='hidden' name='sender_id' ng-value='compose.sender_id' />
755 <input type='hidden' name='sender_name' ng-value='compose.sender_name' />
756 <input type='hidden' name='task' ng-value='compose.task' />
757 <input type='hidden' name='inputBody' ng-value='compose.inputBody' />
758 <input type='hidden' name='pid' ng-value='compose.pid' />
759 <div class='modal-footer'>
760 <button type="button" class="btn btn-secondary"
761 data-dismiss="modal"><?php echo xlt('Cancel'); ?></button>
762 <button type="submit" id="submit" name="submit"
763 class="btn btn-primary float-right" value="messages.php"><?php echo xlt('Send'); ?> <i
764 class="fa fa-arrow-circle-right fa-lg"></i>
765 </button>
766 </div>
767 </form>
768 </div>
769 </div>
770 </div>
771 <!-- /.modal-content -->
772 </div>
773 <!-- /.modal-dialog -->
774 </div>
775 <!-- /.modal compose message -->
776 </div>
777 <!--/row ng-controller-->
778 </div>
779 <!--/container--> </ng>
781 </body>
782 </html>