7 * @link http://www.open-emr.org
8 * @author Jerry Padgett <sjpadgett@gmail.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @author Shiqiang Tao <StrongTSQ@gmail.com>
11 * @author Ben Marte <benmarte@gmail.com>
12 * @copyright Copyright (c) 2016-2022 Jerry Padgett <sjpadgett@gmail.com>
13 * @copyright Copyright (c) 2019-2021 Brady Miller <brady.g.miller@gmail.com>
14 * @copyright Copyright (c) 2020 Shiqiang Tao <StrongTSQ@gmail.com>
15 * @copyright Copyright (c) 2021 Ben Marte <benmarte@gmail.com>
16 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
19 require_once('verify_session.php');
20 require_once("$srcdir/patient.inc.php");
21 require_once("$srcdir/options.inc.php");
22 require_once('lib/portal_mail.inc.php');
23 require_once(__DIR__
. '/../library/appointments.inc.php');
25 use OpenEMR\Common\Csrf\CsrfUtils
;
26 use OpenEMR\Common\Twig\TwigContainer
;
27 use OpenEMR\Events\PatientPortal\RenderEvent
;
28 use OpenEMR\Events\PatientPortal\AppointmentFilterEvent
;
29 use OpenEMR\Services\LogoService
;
31 if (isset($_SESSION['register']) && $_SESSION['register'] === true) {
32 require_once(__DIR__
. '/../src/Common/Session/SessionUtil.php');
33 OpenEMR\Common\Session\SessionUtil
::portalSessionCookieDestroy();
34 header('Location: ' . $landingpage . '&w');
38 if (!isset($_SESSION['portal_init'])) {
39 $_SESSION['portal_init'] = true;
42 $logoService = new LogoService();
45 // Get language definitions for js
46 $language = $_SESSION['language_choice'] ??
'1'; // defaults english
47 $sql = "SELECT c.constant_name, d.definition FROM lang_definitions as d
48 JOIN lang_constants AS c ON d.cons_id = c.cons_id
50 $tarns = sqlStatement($sql, $language);
51 $language_defs = array();
52 while ($row = SqlFetchArray($tarns)) {
53 $language_defs[$row['constant_name']] = $row['definition'];
56 $whereto = $_SESSION['whereto'] ??
null;
58 $user = $_SESSION['sessionUser'] ??
'portal user';
59 $result = getPatientData($pid);
61 $msgs = getPortalPatientNotes($_SESSION['portal_username']);
62 $msgcnt = count($msgs);
64 foreach ($msgs as $i) {
65 if ($i['message_status'] == 'New') {
69 if ($newcnt > 0 && $_SESSION['portal_init']) {
70 $whereto = $_SESSION['whereto'] = '#secure-msgs-card';
72 $messagesURL = $GLOBALS['web_root'] . '/portal/messaging/messages.php';
74 $isEasyPro = $GLOBALS['easipro_enable'] && !empty($GLOBALS['easipro_server']) && !empty($GLOBALS['easipro_name']);
76 $current_date2 = date('Y-m-d');
78 $appts = fetchNextXAppts($current_date2, $pid, $apptLimit);
80 $appointments = array();
83 $stringCM = '(' . xl('Comments field entry present') . ')';
84 $stringR = '(' . xl('Recurring appointment') . ')';
86 foreach ($appts as $row) {
87 $status_title = getListItemTitle('apptstat', $row['pc_apptstatus']);
89 $dayname = xl(date('l', strtotime($row['pc_eventDate'])));
91 $disphour = (int)substr($row['pc_startTime'], 0, 2);
92 $dispmin = substr($row['pc_startTime'], 3, 2);
93 if ($disphour >= 12) {
100 if ($row['pc_hometext'] != '') {
101 $etitle = xl('Comments') . ': ' . $row['pc_hometext'] . "\r\n";
107 'appointmentDate' => $dayname . ', ' . $row['pc_eventDate'] . ' ' . $disphour . ':' . $dispmin . ' ' . $dispampm,
108 'appointmentType' => xl('Type') . ': ' . $row['pc_catname'],
109 'provider' => xl('Provider') . ': ' . $row['ufname'] . ' ' . $row['ulname'],
110 'status' => xl('Status') . ': ' . $status_title,
111 'mode' => (int)$row['pc_recurrtype'] > 0 ?
'recurring' : $row['pc_recurrtype'],
112 'icon_type' => (int)$row['pc_recurrtype'] > 0,
114 'pc_eid' => $row['pc_eid'],
116 $filteredEvent = $GLOBALS['kernel']->getEventDispatcher()->dispatch(new AppointmentFilterEvent($row, $formattedRecord), AppointmentFilterEvent
::EVENT_NAME
);
117 $appointments[] = $filteredEvent->getAppointment() ??
$formattedRecord;
121 function buildNav($newcnt, $pid, $result)
126 'label' => $result['fname'] . ' ' . $result['lname'],
128 'dropdownID' => 'account',
129 'messageCount' => $newcnt ??
0,
132 'url' => '#quickstart-card',
133 'id' => 'quickstart_id',
134 'label' => xl('My Quick Start'),
135 'icon' => 'fa-tasks',
136 'dataToggle' => 'collapse',
140 'url' => '#profilecard',
141 'label' => xl('My Profile'),
143 'dataToggle' => 'collapse',
147 'url' => '#secure-msgs-card',
148 'label' => xl('My Messages'),
149 'icon' => 'fa-envelope',
150 'dataToggle' => 'collapse',
151 'messageCount' => $newcnt ??
0,
155 'url' => '#documentscard',
156 'label' => xl('My Documents'),
157 'icon' => 'fa-file-medical',
158 'dataToggle' => 'collapse'
162 'label' => xl('My Dashboard'),
164 'dataToggle' => 'collapse'
167 'url' => '#openSignModal',
168 'label' => xl('My Signature'),
169 'icon' => 'fa-file-signature',
170 'dataToggle' => 'modal',
171 'dataType' => 'patient-signature'
177 'label' => xl('Reports'),
178 'icon' => 'fa-book-medical',
179 'dropdownID' => 'reports',
182 'url' => $GLOBALS['web_root'] . '' . '/ccdaservice/ccda_gateway.php?action=view&csrf_token_form=' . urlencode(CsrfUtils
::collectCsrfToken()),
183 'label' => xl('View CCD'),
185 'target_blank' => 'true',
188 'url' => $GLOBALS['web_root'] . '' . '/ccdaservice/ccda_gateway.php?action=dl&csrf_token_form=' . urlencode(CsrfUtils
::collectCsrfToken()),
189 'label' => xl('Download CCD'),
190 'icon' => 'fa-download',
195 if (($GLOBALS['portal_two_ledger'] ||
$GLOBALS['portal_two_payments'])) {
196 if (!empty($GLOBALS['portal_two_ledger'])) {
199 'label' => xl('Accountings'),
200 'icon' => 'fa-file-invoice-dollar',
201 'dropdownID' => 'accounting',
204 'url' => '#ledgercard',
205 'label' => xl('Ledger'),
206 'icon' => 'fa-folder-open',
207 'dataToggle' => 'collapse'
214 if ($GLOBALS['easipro_enable'] && !empty($GLOBALS['easipro_server']) && !empty($GLOBALS['easipro_name'])) {
217 'label' => xl('My Assessments'),
218 'icon' => 'fas fa-file-medical',
219 'dataToggle' => 'collapse',
220 'dataType' => 'cardgroup'
224 // Build sub nav items
226 if (!empty($GLOBALS['allow_portal_chat'])) {
228 'url' => '#messagescard',
229 'label' => xl('Chat'),
230 'icon' => 'fa-comment-medical',
231 'dataToggle' => 'collapse',
232 'dataType' => 'cardgroup'
236 for ($i = 0, $iMax = count($navItems); $i < $iMax; $i++
) {
237 if ($GLOBALS['allow_portal_appointments'] && $navItems[$i]['label'] === ($result['fname'] . ' ' . $result['lname'])) {
238 $navItems[$i]['children'][] = [
239 'url' => '#appointmentcard',
240 'label' => xl('My Appointments'),
241 'icon' => 'fa-calendar-check',
242 'dataToggle' => 'collapse'
246 if ($navItems[$i]['label'] === ($result['fname'] . ' ' . $result['lname'])) {
248 $navItems[$i]['children'],
250 'url' => 'javascript:changeCredentials(event)',
251 'label' => xl('Change Credentials'),
252 'icon' => 'fa-cog fa-fw',
255 'url' => 'logout.php',
256 'label' => xl('Logout'),
257 'icon' => 'fa-ban fa-fw',
262 if (!empty($GLOBALS['portal_onsite_document_download']) && $navItems[$i]['label'] === xl('Reports')) {
264 $navItems[$i]['children'],
266 'url' => '#reportcard',
267 'label' => xl('Report Content'),
268 'icon' => 'fa-folder-open',
269 'dataToggle' => 'collapse'
272 'url' => '#downloadcard',
273 'label' => xl('Download Charted Documents'),
274 'icon' => 'fa-download',
275 'dataToggle' => 'collapse'
279 if (!empty($GLOBALS['portal_two_payments']) && $navItems[$i]['label'] === xl('Accountings')) {
280 $navItems[$i]['children'][] = [
281 'url' => '#paymentcard',
282 'label' => xl('Make Payment'),
283 'icon' => 'fa-credit-card',
284 'dataToggle' => 'collapse'
292 $navMenu = buildNav($newcnt, $pid, $result);
294 $twig = (new TwigContainer('', $GLOBALS['kernel']))->getTwig();
295 echo $twig->render('portal/home.html.twig', [
297 'whereto' => $_SESSION['whereto'] ??
null ?
: ($whereto ??
'#quickstart-card'),
302 'menuLogo' => $logoService->getLogo('portal/menu/primary'),
303 'allow_portal_appointments' => $GLOBALS['allow_portal_appointments'],
304 'web_root' => $GLOBALS['web_root'],
305 'payment_gateway' => $GLOBALS['payment_gateway'],
306 'gateway_mode_production' => $GLOBALS['gateway_mode_production'],
307 'portal_two_payments' => $GLOBALS['portal_two_payments'],
308 'allow_portal_chat' => $GLOBALS['allow_portal_chat'],
309 'portal_onsite_document_download' => $GLOBALS['portal_onsite_document_download'],
310 'portal_two_ledger' => $GLOBALS['portal_two_ledger'],
311 'images_static_relative' => $GLOBALS['images_static_relative'],
312 'youHave' => xl('You have'),
313 'navMenu' => $navMenu,
314 'primaryMenuLogoHeight' => $GLOBALS['portal_primary_menu_logo_height'] ??
'30',
315 'pagetitle' => xl('Home') . ' | ' . $GLOBALS['openemr_name'] . ' ' . xl('Portal'),
316 'messagesURL' => $messagesURL,
318 'patientName' => $_SESSION['ptName'] ??
null,
319 'csrfUtils' => CsrfUtils
::collectCsrfToken(),
320 'isEasyPro' => $isEasyPro,
321 'appointments' => $appointments,
323 'appointmentLimit' => $apptLimit,
324 'appointmentCount' => $count ??
null,
325 'displayLimitLabel' => xl('Display limit reached'),
326 'site_id' => $_SESSION['site_id'] ??
($_GET['site'] ??
'default'), // one way or another, we will have a site_id.
327 'portal_timeout' => $GLOBALS['portal_timeout'] ??
1800, // timeout is in seconds
328 'language_defs' => $language_defs,
330 'sectionRenderPost' => RenderEvent
::EVENT_SECTION_RENDER_POST
,
331 'scriptsRenderPre' => RenderEvent
::EVENT_SCRIPTS_RENDER_PRE