Change support desk contact information (#7561)
[openemr.git] / portal / home.php
blobc7feea360b2ee3ced603a9b21e23d1c6c759e69a
1 <?php
3 /**
4 * Patient Portal Home
6 * @package OpenEMR
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-2023 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;
30 use Twig\Error\LoaderError;
31 use Twig\Error\RuntimeError;
32 use Twig\Error\SyntaxError;
34 if (isset($_SESSION['register']) && $_SESSION['register'] === true) {
35 require_once(__DIR__ . '/../src/Common/Session/SessionUtil.php');
36 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
37 header('Location: ' . $landingpage . '&w');
38 exit();
41 if (!isset($_SESSION['portal_init'])) {
42 $_SESSION['portal_init'] = true;
45 $logoService = new LogoService();
48 // Get language definitions for js
49 $language = $_SESSION['language_choice'] ?? '1'; // defaults english
50 $sql = "SELECT c.constant_name, d.definition FROM lang_definitions as d
51 JOIN lang_constants AS c ON d.cons_id = c.cons_id
52 WHERE d.lang_id = ?";
53 $tarns = sqlStatement($sql, $language);
54 $language_defs = array();
55 while ($row = SqlFetchArray($tarns)) {
56 $language_defs[$row['constant_name']] = $row['definition'];
59 $whereto = $_SESSION['whereto'] ?? null;
61 $user = $_SESSION['sessionUser'] ?? 'portal user';
62 $result = getPatientData($pid);
64 $msgs = getPortalPatientNotes($_SESSION['portal_username']);
65 $msgcnt = count($msgs);
66 $newcnt = 0;
67 foreach ($msgs as $i) {
68 if ($i['message_status'] == 'New') {
69 $newcnt += 1;
72 if ($newcnt > 0 && $_SESSION['portal_init']) {
73 $whereto = $_SESSION['whereto'] = '#secure-msgs-card';
75 $messagesURL = $GLOBALS['web_root'] . '/portal/messaging/messages.php';
77 $isEasyPro = $GLOBALS['easipro_enable'] && !empty($GLOBALS['easipro_server']) && !empty($GLOBALS['easipro_name']);
79 $current_date2 = date('Y-m-d');
80 $apptLimit = 30;
81 $appts = fetchNextXAppts($current_date2, $pid, $apptLimit);
83 $appointments = array();
84 if ($appts) {
85 $stringCM = '(' . xl('Comments field entry present') . ')';
86 $stringR = '(' . xl('Recurring appointment') . ')';
87 $count = 0;
88 foreach ($appts as $row) {
89 $status_title = getListItemTitle('apptstat', $row['pc_apptstatus']);
90 $count++;
91 $dayname = xl(date('l', strtotime($row['pc_eventDate'])));
92 $dispampm = 'am';
93 $disphour = (int)substr($row['pc_startTime'], 0, 2);
94 $dispmin = substr($row['pc_startTime'], 3, 2);
95 if ($disphour >= 12) {
96 $dispampm = 'pm';
97 if ($disphour > 12) {
98 $disphour -= 12;
102 if ($row['pc_hometext'] != '') {
103 $etitle = xl('Comments') . ': ' . $row['pc_hometext'] . "\r\n";
104 } else {
105 $etitle = '';
108 $formattedRecord = [
109 'appointmentDate' => $dayname . ', ' . $row['pc_eventDate'] . ' ' . $disphour . ':' . $dispmin . ' ' . $dispampm,
110 'appointmentType' => xl('Type') . ': ' . $row['pc_catname'],
111 'provider' => xl('Provider') . ': ' . $row['ufname'] . ' ' . $row['ulname'],
112 'status' => xl('Status') . ': ' . $status_title,
113 'mode' => (int)$row['pc_recurrtype'] > 0 ? 'recurring' : $row['pc_recurrtype'],
114 'icon_type' => (int)$row['pc_recurrtype'] > 0,
115 'etitle' => $etitle,
116 'pc_eid' => $row['pc_eid'],
118 $filteredEvent = $GLOBALS['kernel']->getEventDispatcher()->dispatch(new AppointmentFilterEvent($row, $formattedRecord), AppointmentFilterEvent::EVENT_NAME);
119 $appointments[] = $filteredEvent->getAppointment() ?? $formattedRecord;
123 $current_theme = sqlQuery("SELECT `setting_value` FROM `patient_settings` WHERE setting_patient = ? AND `setting_label` = ?", array($pid, 'portal_theme'))['setting_value'] ?? '';
124 function collectStyles(): array
126 global $webserver_root;
127 $theme_dir = "$webserver_root/public/themes";
128 $dh = opendir($theme_dir);
129 $styleArray = array();
130 while (false !== ($tfname = readdir($dh))) {
131 if (
132 $tfname == 'style_blue.css' ||
133 $tfname == 'style_pdf.css' ||
134 !preg_match("/^" . 'style_' . ".*\.css$/", $tfname)
136 continue;
138 $styleDisplayName = str_replace("_", " ", substr($tfname, 6));
139 $styleDisplayName = ucfirst(str_replace(".css", "", $styleDisplayName));
140 $styleArray[$tfname] = $styleDisplayName;
142 asort($styleArray);
143 closedir($dh);
144 return $styleArray;
146 function buildNav($newcnt, $pid, $result)
148 $navItems = [
150 'url' => '#',
151 'label' => $result['fname'] . ' ' . $result['lname'],
152 'icon' => 'fa-user',
153 'dropdownID' => 'account',
154 'messageCount' => $newcnt ?? 0,
155 'children' => [
157 'url' => '#quickstart-card',
158 'id' => 'quickstart_id',
159 'label' => xl('My Dashboard'),
160 'icon' => 'fa-tasks',
161 'dataToggle' => 'collapse',
165 'url' => '#profilecard',
166 'label' => xl('My Profile'),
167 'icon' => 'fa-user',
168 'dataToggle' => 'collapse',
172 'url' => '#secure-msgs-card',
173 'label' => xl('My Messages'),
174 'icon' => 'fa-envelope',
175 'dataToggle' => 'collapse',
176 'messageCount' => $newcnt ?? 0,
178 /* Reserve item */
180 'url' => '#documentscard',
181 'label' => xl('My Documents'),
182 'icon' => 'fa-file-medical',
183 'dataToggle' => 'collapse'
184 ],*/
186 'url' => '#lists',
187 'label' => xl('My Health'),
188 'icon' => 'fa-list',
189 'dataToggle' => 'collapse'
192 'url' => '#openSignModal',
193 'label' => xl('My Signature'),
194 'icon' => 'fa-file-signature',
195 'dataToggle' => 'modal',
196 'dataType' => 'patient-signature'
201 'url' => '#',
202 'label' => xl('Reports'),
203 'icon' => 'fa-book-medical',
204 'dropdownID' => 'reports',
205 'children' => [
207 'url' => $GLOBALS['web_root'] . '' . '/ccdaservice/ccda_gateway.php?action=view&csrf_token_form=' . urlencode(CsrfUtils::collectCsrfToken()),
208 'label' => xl('View CCD'),
209 'icon' => 'fa-eye',
210 'target_blank' => 'true',
213 'url' => $GLOBALS['web_root'] . '' . '/ccdaservice/ccda_gateway.php?action=dl&csrf_token_form=' . urlencode(CsrfUtils::collectCsrfToken()),
214 'label' => xl('Download CCD'),
215 'icon' => 'fa-download',
220 if (($GLOBALS['portal_two_ledger'] || $GLOBALS['portal_two_payments'])) {
221 if (!empty($GLOBALS['portal_two_ledger'])) {
222 $navItems[] = [
223 'url' => '#',
224 'label' => xl('Accountings'),
225 'icon' => 'fa-file-invoice-dollar',
226 'dropdownID' => 'accounting',
227 'children' => [
229 'url' => '#ledgercard',
230 'label' => xl('Ledger'),
231 'icon' => 'fa-folder-open',
232 'dataToggle' => 'collapse'
239 if ($GLOBALS['easipro_enable'] && !empty($GLOBALS['easipro_server']) && !empty($GLOBALS['easipro_name'])) {
240 $navItems[] = [
241 'url' => '#procard',
242 'label' => xl('My Assessments'),
243 'icon' => 'fas fa-file-medical',
244 'dataToggle' => 'collapse',
245 'dataType' => 'cardgroup'
249 // Build sub nav items
251 if (!empty($GLOBALS['allow_portal_chat'])) {
252 $navItems[] = [
253 'url' => '#messagescard',
254 'label' => xl('Chat'),
255 'icon' => 'fa-comment-medical',
256 'dataToggle' => 'collapse',
257 'dataType' => 'cardgroup'
261 for ($i = 0, $iMax = count($navItems); $i < $iMax; $i++) {
262 if ($GLOBALS['allow_portal_appointments'] && $navItems[$i]['label'] === ($result['fname'] . ' ' . $result['lname'])) {
263 $navItems[$i]['children'][] = [
264 'url' => '#appointmentcard',
265 'label' => xl('My Appointments'),
266 'icon' => 'fa-calendar-check',
267 'dataToggle' => 'collapse'
271 if ($navItems[$i]['label'] === ($result['fname'] . ' ' . $result['lname'])) {
272 array_push(
273 $navItems[$i]['children'],
275 'url' => 'javascript:changeCredentials(event)',
276 'label' => xl('Change Credentials'),
277 'icon' => 'fa-cog fa-fw',
280 'url' => 'logout.php',
281 'label' => xl('Logout'),
282 'icon' => 'fa-ban fa-fw',
287 if (!empty($GLOBALS['portal_onsite_document_download']) && $navItems[$i]['label'] === xl('Reports')) {
288 array_push(
289 $navItems[$i]['children'],
291 'url' => '#reportcard',
292 'label' => xl('Report Content'),
293 'icon' => 'fa-folder-open',
294 'dataToggle' => 'collapse'
297 'url' => '#downloadcard',
298 'label' => xl('Download Charted Documents'),
299 'icon' => 'fa-download',
300 'dataToggle' => 'collapse'
304 if (!empty($GLOBALS['portal_two_payments']) && $navItems[$i]['label'] === xl('Accountings')) {
305 $navItems[$i]['children'][] = [
306 'url' => '#paymentcard',
307 'label' => xl('Make Payment'),
308 'icon' => 'fa-credit-card',
309 'dataToggle' => 'collapse'
314 return $navItems;
316 // Available Themes
317 $styleArray = collectStyles();
318 // Build our navigation
319 $navMenu = buildNav($newcnt, $pid, $result);
320 // Render Home Page
321 $twig = (new TwigContainer('', $GLOBALS['kernel']))->getTwig();
322 try {
323 echo $twig->render('portal/home.html.twig', [
324 'user' => $user,
325 'whereto' => $_SESSION['whereto'] ?? null ?: ($whereto ?? '#quickstart-card'),
326 'result' => $result,
327 'msgs' => $msgs,
328 'msgcnt' => $msgcnt,
329 'newcnt' => $newcnt,
330 'menuLogo' => $logoService->getLogo('portal/menu/primary'),
331 'allow_portal_appointments' => $GLOBALS['allow_portal_appointments'],
332 'web_root' => $GLOBALS['web_root'],
333 'payment_gateway' => $GLOBALS['payment_gateway'],
334 'gateway_mode_production' => $GLOBALS['gateway_mode_production'],
335 'portal_two_payments' => $GLOBALS['portal_two_payments'],
336 'allow_portal_chat' => $GLOBALS['allow_portal_chat'],
337 'portal_onsite_document_download' => $GLOBALS['portal_onsite_document_download'],
338 'portal_two_ledger' => $GLOBALS['portal_two_ledger'],
339 'images_static_relative' => $GLOBALS['images_static_relative'],
340 'youHave' => xl('You have'),
341 'navMenu' => $navMenu,
342 'primaryMenuLogoHeight' => $GLOBALS['portal_primary_menu_logo_height'] ?? '30',
343 'pagetitle' => xl('Home') . ' | ' . $GLOBALS['openemr_name'] . ' ' . xl('Portal'),
344 'messagesURL' => $messagesURL,
345 'patientID' => $pid,
346 'patientName' => $_SESSION['ptName'] ?? null,
347 'csrfUtils' => CsrfUtils::collectCsrfToken(),
348 'isEasyPro' => $isEasyPro,
349 'appointments' => $appointments,
350 'appts' => $appts,
351 'appointmentLimit' => $apptLimit,
352 'appointmentCount' => $count ?? null,
353 'displayLimitLabel' => xl('Display limit reached'),
354 'site_id' => $_SESSION['site_id'] ?? ($_GET['site'] ?? 'default'), // one way or another, we will have a site_id.
355 'portal_timeout' => $GLOBALS['portal_timeout'] ?? 1800, // timeout is in seconds
356 'language_defs' => $language_defs,
357 'current_theme' => $current_theme,
358 'styleArray' => $styleArray,
359 'eventNames' => [
360 'sectionRenderPost' => RenderEvent::EVENT_SECTION_RENDER_POST,
361 'scriptsRenderPre' => RenderEvent::EVENT_SCRIPTS_RENDER_PRE,
362 'dashboardInjectCard' => RenderEvent::EVENT_DASHBOARD_INJECT_CARD,
363 'dashboardRenderScripts' => RenderEvent::EVENT_DASHBOARD_RENDER_SCRIPTS
366 } catch (LoaderError | RuntimeError | SyntaxError $e) {
367 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
368 die(text($e->getMessage()));