Add back popup dialogs for tabs U.I. (#1434)
[openemr.git] / portal / account / register.php
bloba8bc80e21a05774b4ad2d016751216e918207f27
1 <?php
2 /**
3 * Portal Registration Wizard
5 * @package OpenEMR
6 * @link http://www.open-emr.org
7 * @author Jerry Padgett <sjpadgett@gmail.com>
8 * @copyright Copyright (c) 2017-2018 Jerry Padgett <sjpadgett@gmail.com>
9 * @license https://www.gnu.org/licenses/agpl-3.0.en.html GNU Affero General Public License 3
12 session_start();
13 session_regenerate_id(true);
15 unset($_SESSION['itsme']);
16 $_SESSION['patient_portal_onsite_two'] = true;
17 $_SESSION['authUser'] = 'portal-user';
18 $_SESSION['pid'] = true;
19 $_SESSION['register'] = true;
21 $_SESSION['site_id'] = isset($_SESSION['site_id']) ? $_SESSION['site_id'] : 'default';
22 $landingpage = "index.php?site=" . $_SESSION['site_id'];
24 $ignoreAuth_onsite_portal_two = true;
26 require_once("../../interface/globals.php");
28 $res2 = sqlStatement("select * from lang_languages where lang_description = ?", array(
29 $GLOBALS['language_default']
30 ));
31 for ($iter = 0; $row = sqlFetchArray($res2); $iter ++) {
32 $result2[$iter] = $row;
34 if (count($result2) == 1) {
35 $defaultLangID = $result2[0]{"lang_id"};
36 $defaultLangName = $result2[0]{"lang_description"};
37 } else {
38 // default to english if any problems
39 $defaultLangID = 1;
40 $defaultLangName = "English";
43 if (! isset($_SESSION['language_choice'])) {
44 $_SESSION['language_choice'] = $defaultLangID;
46 // collect languages if showing language menu
47 if ($GLOBALS['language_menu_login']) {
48 // sorting order of language titles depends on language translation options.
49 $mainLangID = empty($_SESSION['language_choice']) ? '1' : $_SESSION['language_choice'];
50 if ($mainLangID == '1' && ! empty($GLOBALS['skip_english_translation'])) {
51 $sql = "SELECT * FROM lang_languages ORDER BY lang_description, lang_id";
52 $res3 = SqlStatement($sql);
53 } else {
54 // Use and sort by the translated language name.
55 $sql = "SELECT ll.lang_id, " . "IF(LENGTH(ld.definition),ld.definition,ll.lang_description) AS trans_lang_description, " . "ll.lang_description " .
56 "FROM lang_languages AS ll " . "LEFT JOIN lang_constants AS lc ON lc.constant_name = ll.lang_description " .
57 "LEFT JOIN lang_definitions AS ld ON ld.cons_id = lc.cons_id AND " . "ld.lang_id = ? " .
58 "ORDER BY IF(LENGTH(ld.definition),ld.definition,ll.lang_description), ll.lang_id";
59 $res3 = SqlStatement($sql, array(
60 $mainLangID
61 ));
64 for ($iter = 0; $row = sqlFetchArray($res3); $iter ++) {
65 $result3[$iter] = $row;
68 if (count($result3) == 1) {
69 // default to english if only return one language
70 $hiddenLanguageField = "<input type='hidden' name='languageChoice' value='1' />\n";
72 } else {
73 $hiddenLanguageField = "<input type='hidden' name='languageChoice' value='" . htmlspecialchars($defaultLangID, ENT_QUOTES) . "' />\n";
77 <!DOCTYPE html>
78 <html>
79 <head>
80 <title><?php echo xlt('New Patient'); ?> | <?php echo xlt('Register'); ?></title>
81 <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
82 <meta name="description" content="Developed By sjpadgett@gmail.com">
84 <link href="<?php echo $GLOBALS['assets_static_relative']; ?>/font-awesome-4-6-3/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
85 <link rel="stylesheet" href="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-datetimepicker-2-5-4/build/jquery.datetimepicker.min.css">
86 <link href="<?php echo $GLOBALS['assets_static_relative']; ?>/bootstrap-3-3-4/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
87 <link href="./../assets/css/register.css" rel="stylesheet" type="text/css" />
89 <script src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-min-3-1-1/index.js" type="text/javascript"></script>
91 <script src="<?php echo $GLOBALS['assets_static_relative']; ?>/bootstrap-3-3-4/dist/js/bootstrap.min.js" type="text/javascript"></script>
92 <script type="text/javascript" src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-datetimepicker-2-5-4/build/jquery.datetimepicker.full.min.js"></script>
93 <script type="text/javascript" src="<?php echo $GLOBALS['assets_static_relative']; ?>/emodal-1-2-65/dist/eModal.js"></script>
95 <script>
96 var newPid = 0;
97 var curPid = 0;
98 var provider = 0;
100 $(document).ready(function () {
101 /* // test data
102 $("#emailInput").val("me@me.com");
103 $("#fname").val("Jerry");
104 $("#lname").val("Padgett");
105 $("#dob").val("1919-03-03");
106 // ---------- */
107 var navListItems = $('div.setup-panel div a'),
108 allWells = $('.setup-content'),
109 allNextBtn = $('.nextBtn'),
110 allPrevBtn = $('.prevBtn');
112 allWells.hide();
114 navListItems.click(function (e) {
115 e.preventDefault();
116 var $target = $($(this).attr('href')),
117 $item = $(this);
119 if (!$item.hasClass('disabled')) {
120 navListItems.removeClass('btn-primary').addClass('btn-default');
121 $item.addClass('btn-primary');
122 allWells.hide();
123 $target.show();
124 $target.find('input:eq(0)').focus();
128 allPrevBtn.click(function () {
129 var curStep = $(this).closest(".setup-content"),
130 curStepBtn = curStep.attr("id"),
131 prevstepwiz = $('div.setup-panel div a[href="#' + curStepBtn + '"]').parent().prev().children("a");
132 prevstepwiz.removeAttr('disabled').trigger('click');
135 allNextBtn.click(function () {
136 var profile = $("#profileFrame").contents();
138 /* // test data
139 profile.find("input#street").val("123 Some St.");
140 profile.find("input#city").val("Brandon");
141 //--------------------- */
143 var curStep = $(this).closest(".setup-content"),
144 curStepBtn = curStep.attr("id"),
145 nextstepwiz = $('div.setup-panel div a[href="#' + curStepBtn + '"]').parent().next().children("a"),
146 curInputs = curStep.find("input[type='text'],input[type='email'],select"),
147 isValid = true;
149 $(".form-group").removeClass("has-error");
150 for (var i = 0; i < curInputs.length; i++) {
151 if (!curInputs[i].validity.valid) {
152 isValid = false;
153 $(curInputs[i]).closest(".form-group").addClass("has-error");
156 if (isValid) {
157 if (curStepBtn == 'step-1') { // leaving step 1 setup profile frame. Prob not nec but in case
158 profile.find('input#fname').val($("#fname").val());
159 profile.find('input#mname').val($("#mname").val());
160 profile.find('input#lname').val($("#lname").val());
161 profile.find('input#dob').val($("#dob").val());
162 profile.find('input#email').val($("#emailInput").val());
163 profile.find('input[name=allowPatientPortal]').val(['YES']);
164 // need these for validation.
165 profile.find('select#providerid option:contains("Unassigned")').val('');
166 profile.find('select#providerid').attr('required', true);
167 profile.find('select#sex option:contains("Unassigned")').val('');
168 profile.find('select#sex').attr('required', true);
170 var pid = profile.find('input#pid').val();
171 if (pid < 1) { // form pid set in promise
172 callServer('get_newpid', '', $("#dob").val(), $("#lname").val(), $("#fname").val()); // @TODO escape these
175 nextstepwiz.removeAttr('disabled').trigger('click');
179 $("#profileNext").click(function () {
180 var profile = $("#profileFrame").contents();
181 var curStep = $(this).closest(".setup-content"),
182 curStepBtn = curStep.attr("id"),
183 nextstepwiz = $('div.setup-panel div a[href="#' + curStepBtn + '"]').parent().next().children("a"),
184 curInputs = $("#profileFrame").contents().find("input[type='text'],input[type='email'],select"),
185 isValid = true;
186 $(".form-group").removeClass("has-error");
187 var flg = 0;
188 for (var i = 0; i < curInputs.length; i++) {
189 if (!curInputs[i].validity.valid) {
190 isValid = false;
191 if (!flg) {
192 curInputs[i].scrollIntoView();
193 curInputs[i].focus();
194 flg = 1;
196 $(curInputs[i]).closest(".form-group").addClass("has-error");
199 if (isValid) {
200 provider = profile.find('select#providerid').val();
201 nextstepwiz.removeAttr('disabled').trigger('click');
205 $("#submitPatient").click(function () {
206 var profile = $("#profileFrame").contents();
207 var pid = profile.find('input#pid').val();
209 if (pid < 1) { // Just in case. Can never have too many pid checks!
210 callServer('get_newpid', '');
213 var isOk = checkRegistration(newPid);
214 if (isOk) {
215 // Use portals rest api. flag 1 is write to chart. flag 0 writes an audit record for review in dashboard.
216 // rest update will determine if new or existing pid for save. In register step-1 we catch existing pid but,
217 // we can still use update here if we want to allow changing passwords.
219 document.getElementById('profileFrame').contentWindow.page.updateModel(1);
220 $("#insuranceForm").submit();
221 // cleanup is in callServer done promise. This starts end session.
225 $('div.setup-panel div a.btn-primary').trigger('click');
227 $('.datepicker').datetimepicker({
228 <?php $datetimepicker_timepicker = false; ?>
229 <?php $datetimepicker_showseconds = false; ?>
230 <?php $datetimepicker_formatInput = false; ?>
231 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
234 $("#insuranceForm").submit(function (e) {
235 e.preventDefault();
236 var url = "account.php?action=new_insurance&pid=" + newPid;
237 $.ajax({
238 url: url,
239 type: 'post',
240 data: $("#insuranceForm").serialize(),
241 success: function (serverResponse) {
242 doCredentials(newPid) // this is the end for session.
243 return false;
248 $('#selLanguage').on('change', function () {
249 callServer("set_lang", this.value);
252 $(document.body).on('hidden.bs.modal', function () { //@TODO maybe make a promise for wiz exit
253 callServer('cleanup');
256 $('#inscompany').on('change', function () {
257 if ($('#inscompany').val().toUpperCase() === 'SELF') {
258 $("#insuranceForm input").removeAttr("required");
259 let message = "<?php echo xls('You have chosen to be self insured or currently do not have insurance. Click next to continue registration.'); ?>";
260 alert(message);
264 }); // ready end
266 function doCredentials(pid) {
267 callServer('do_signup', pid);
270 function checkRegistration(pid) {
271 var profile = $("#profileFrame").contents();
272 var curStep = $("#step-2"),
273 curStepBtn = curStep.attr("id"),
274 nextstepwiz = $('div.setup-panel div a[href="#' + curStepBtn + '"]').parent().next().children("a"),
275 curInputs = $("#profileFrame").contents().find("input[type='text'],input[type='email'],select"),
276 isValid = true;
277 $(".form-group").removeClass("has-error");
278 var flg = 0;
279 for (var i = 0; i < curInputs.length; i++) {
280 if (!curInputs[i].validity.valid) {
281 isValid = false;
282 if (!flg) {
283 curInputs[i].scrollIntoView();
284 curInputs[i].focus();
285 flg = 1;
287 $(curInputs[i]).closest(".form-group").addClass("has-error");
291 if (!isValid) {
292 return false;
295 return true;
298 function callServer(action, value, value2, last, first) {
299 var data = {
300 'action' : action,
301 'value' : value,
302 'dob' : value2,
303 'last' : last,
304 'first' : first
306 if (action == 'do_signup') {
307 data = {
308 'action': action,
309 'pid': value
312 else if (action == 'notify_admin') {
313 data = {
314 'action': action,
315 'pid': value,
316 'provider': value2
319 else if (action == 'cleanup') {
320 data = {
321 'action': action
324 // The magic that is jquery ajax.
325 $.ajax({
326 type : 'GET',
327 url : 'account.php',
328 data : data
329 }).done(function (rtn) {
330 if (action == "cleanup") {
331 window.location.href = "./../index.php" // Goto landing page.
333 else if (action == "set_lang") {
334 window.location.href = window.location.href;
336 else if (action == "get_newpid") {
337 if (parseInt(rtn) > 0) {
338 newPid = rtn;
339 $("#profileFrame").contents().find('input#pubpid').val(newPid);
340 $("#profileFrame").contents().find('input#pid').val(newPid);
342 else {
343 // After error alert app exit to landing page.
344 // Existing user error. Error message is translated in account.lib.php.
345 eModal.alert(rtn);
348 else if (action == 'do_signup') {
349 if (rtn == "") {
350 let message = "<?php echo xls('Unable to either create credentials or send email.'); ?>";
351 alert(message);
352 return false;
354 // For production. Here we're finished so do signup closing alert and then cleanup.
355 callServer('notify_admin', newPid, provider); // pnote notify to selected provider
356 // alert below for ease of testing.
357 //alert(rtn); // sync alert.. rtn holds username and password for testing.
359 let message = "<?php echo xls("Your new credentials have been sent. Check your email inbox and also possibly your spam folder. Once you log into your patient portal feel free to make an appointment or send us a secure message. We look forward to seeing you soon."); ?>"
360 eModal.alert(message); // This is an async call. The modal close event exits us to portal landing page after cleanup.
362 }).fail(function (err) {
363 let message = "<?php echo xls('Something went wrong.') ?>";
364 alert(message);
367 </script>
368 </head>
369 <body class="skin-blue">
370 <div class="container">
371 <div class="stepwiz col-md-offset-3">
372 <div class="stepwiz-row setup-panel">
373 <div class="stepwiz-step">
374 <a href="#step-1" type="button" class="btn btn-primary btn-circle">1</a>
375 <p><?php echo xlt('Get Started') ?></p>
376 </div>
377 <div class="stepwiz-step">
378 <a href="#step-2" type="button" class="btn btn-default btn-circle" disabled="disabled">2</a>
379 <p><?php echo xlt('Profile') ?></p>
380 </div>
381 <div class="stepwiz-step">
382 <a href="#step-3" type="button" class="btn btn-default btn-circle" disabled="disabled">3</a>
383 <p><?php echo xlt('Insurance') ?></p>
384 </div>
385 <div class="stepwiz-step">
386 <a href="#step-4" type="button" class="btn btn-default btn-circle" disabled="disabled"><?php echo xlt('Done') ?></a>
387 <p><?php echo xlt('Register') ?></p>
388 </div>
389 </div>
390 </div>
391 <!-- // Start Forms // -->
392 <form class="form-inline" id="startForm" role="form" action="" method="post" onsubmit="">
393 <div class="row setup-content" id="step-1">
394 <div class="col-xs-7 col-md-offset-3 text-center">
395 <fieldset>
396 <legend class='bg-primary'><?php echo xlt('Contact') ?></legend>
397 <div class="well">
398 <?php if ($GLOBALS['language_menu_login']) { ?>
399 <?php if (count($result3) != 1) { ?>
400 <div class="form-group row">
401 <label for="selLanguage"><?php echo xlt('Language'); ?></label>
402 <select class="form-control" id="selLanguage" name="languageChoice">
403 <?php
404 echo "<option selected='selected' value='" . htmlspecialchars($defaultLangID, ENT_QUOTES) . "'>" .
405 htmlspecialchars(xl('Default') . " - " . xl($defaultLangName), ENT_NOQUOTES) . "</option>\n";
406 foreach ($result3 as $iter) {
407 if ($GLOBALS['language_menu_showall']) {
408 if (! $GLOBALS['allow_debug_language'] && $iter['lang_description'] == 'dummy') {
409 continue; // skip the dummy language
411 echo "<option value='" . htmlspecialchars($iter['lang_id'], ENT_QUOTES) . "'>" .
412 htmlspecialchars($iter['trans_lang_description'], ENT_NOQUOTES) . "</option>\n";
413 } else {
414 if (in_array($iter['lang_description'], $GLOBALS['language_menu_show'])) {
415 if (! $GLOBALS['allow_debug_language'] && $iter['lang_description'] == 'dummy') {
416 continue; // skip the dummy language
418 echo "<option value='" . htmlspecialchars($iter['lang_id'], ENT_QUOTES) . "'>" .
419 htmlspecialchars($iter['trans_lang_description'], ENT_NOQUOTES) . "</option>\n";
424 </select>
425 </div>
426 <?php } } ?>
427 <div class="row">
428 <div class="col-sm-12">
429 <div class="form-group inline">
430 <label class="control-label" for="fname"><?php echo xlt('First')?></label>
431 <div class="controls inline-inputs">
432 <input type="text" class="form-control" id="fname" required placeholder="<?php echo xla('First Name'); ?>">
433 </div>
434 </div>
435 <div class="form-group inline">
436 <label class="control-label" for="mname"><?php echo xlt('Middle')?></label>
437 <div class="controls inline-inputs">
438 <input type="text" class="form-control" id="mname" placeholder="<?php echo xla('Full or Initial'); ?>">
439 </div>
440 </div>
441 <div class="form-group inline">
442 <label class="control-label" for="lname"><?php echo xlt('Last Name')?></label>
443 <div class="controls inline-inputs">
444 <input type="text" class="form-control" id="lname" required placeholder="<?php echo xla('Enter Last'); ?>">
445 </div>
446 </div>
447 </div>
448 </div>
449 <div class="form-group inline">
450 <label class="control-label" for="dob"><?php echo xlt('Birth Date')?></label>
451 <div class="controls inline-inputs">
452 <div class="input-group">
453 <input id="dob" type="text" required class="form-control datepicker" placeholder="<?php echo xla('YYYY-MM-DD'); ?>" />
454 </div>
455 </div>
456 </div>
457 <div class="row">
458 <div class="col-sm-12 form-group">
459 <label class="control-label" for="email"><?php echo xlt('Enter E-Mail Address')?></label>
460 <div class="controls inline-inputs">
461 <input id="emailInput" type="email" class="form-control" style="width: 100%" required
462 placeholder="<?php echo xla('Enter email address to receive registration.'); ?>" maxlength="100">
463 </div>
464 </div>
465 </div>
466 </div>
467 <button class="btn btn-primary nextBtn btn-sm pull-right" type="button"><?php echo xlt('Next') ?></button>
468 </fieldset>
469 </div>
470 </div>
471 </form>
472 <!-- Profile Form -->
473 <form class="form-inline" id="profileForm" role="form" action="account.php" method="post">
474 <div class="row setup-content" id="step-2" style="display: none">
475 <div class="col-md-9 col-md-offset-2 text-center">
476 <fieldset>
477 <legend class='bg-primary'><?php echo xlt('Profile') ?></legend>
478 <div class="well">
479 <div class="embed-responsive embed-responsive-16by9">
480 <iframe class="embed-responsive-item" src="../patient/patientdata?pid=0&register=true" id="profileFrame" name="demo"></iframe>
481 </div>
482 </div>
483 <button class="btn btn-primary prevBtn btn-sm pull-left" type="button"><?php echo xlt('Previous') ?></button>
484 <button class="btn btn-primary btn-sm pull-right" type="button" id="profileNext"><?php echo xlt('Next') ?></button>
485 </fieldset>
486 </div>
487 </div>
488 </form>
489 <!-- Insurance Form -->
490 <form class="form-inline" id="insuranceForm" role="form" action="" method="post">
491 <div class="row setup-content" id="step-3" style="display: none">
492 <div class="col-xs-6 col-md-offset-3 text-center">
493 <fieldset>
494 <legend class='bg-primary'><?php echo xlt('Insurance') ?></legend>
495 <div class="well">
496 <div class="form-group inline">
497 <label class="control-label" for="provider"><?php echo xlt('Insurance Company')?></label>
498 <div class="controls inline-inputs">
499 <input type="text" class="form-control" name="provider" id="inscompany" required placeholder="<?php echo xla('Enter Self if None'); ?>">
500 </div>
501 </div>
502 <div class="form-group inline">
503 <label class="control-label" for=""><?php echo xlt('Plan Name')?></label>
504 <div class="controls inline-inputs">
505 <input type="text" class="form-control" name="plan_name" required placeholder="<?php echo xla('Required'); ?>">
506 </div>
507 </div>
508 <div class="form-group inline">
509 <label class="control-label" for=""><?php echo xlt('Policy Number')?></label>
510 <div class="controls inline-inputs">
511 <input type="text" class="form-control" name="policy_number" required placeholder="<?php echo xla('Required'); ?>">
512 </div>
513 </div>
514 <div class="form-group inline">
515 <label class="control-label" for=""><?php echo xlt('Group Number')?></label>
516 <div class="controls inline-inputs">
517 <input type="text" class="form-control" name="group_number" required placeholder="<?php echo xla('Required'); ?>">
518 </div>
519 </div>
520 <div class="form-group inline">
521 <label class="control-label" for=""><?php echo xlt('Policy Begin Date')?></label>
522 <div class="controls inline-inputs">
523 <input type="text" class="form-control datepicker" name="date" placeholder="<?php echo xla('Policy effective date'); ?>">
524 </div>
525 </div>
526 <div class="form-group inline">
527 <label class="control-label" for=""><?php echo xlt('Co-Payment')?></label>
528 <div class="controls inline-inputs">
529 <input type="number" class="form-control" name="copay" placeholder="<?php echo xla('Plan copay if known'); ?>">
530 </div>
531 </div>
532 </div>
533 <button class="btn btn-primary prevBtn btn-sm pull-left" type="button"><?php echo xlt('Previous') ?></button>
534 <button class="btn btn-primary nextBtn btn-sm pull-right" type="button"><?php echo xlt('Next') ?></button>
535 </fieldset>
536 </div>
537 </div>
538 </form>
539 <!-- End Insurance. Next what we've been striving towards..the end-->
540 <div class="row setup-content" id="step-4" style="display: none">
541 <div class="col-xs-6 col-md-offset-3 text-center">
542 <div class="col-md-12">
543 <fieldset>
544 <legend class='bg-success'><?php echo xlt('Register') ?></legend>
545 <div class="well" style="text-align: center">
546 <h4 class='bg-success'><?php echo xlt("All set. Click Send Request below to finish registration") ?></h4>
547 <hr>
549 <?php echo xlt("An e-mail with your new account credentials will be sent to the e-mail address supplied earlier. You may still review or edit any part of your information by using the top step buttons to go to the appropriate panels. Note to be sure you have given your correct e-mail address. If after receiving credentials and you have trouble with access to the portal, please contact administration.") ?>
550 </p>
551 </div>
552 <button class="btn btn-primary prevBtn btn-sm pull-left" type="button"><?php echo xlt('Previous') ?></button>
553 <hr>
554 <button class="btn btn-success btn-sm pull-right" type="button" id="submitPatient"><?php echo xlt('Send Request') ?></button>
555 </fieldset>
556 </div>
557 </div>
558 </div>
559 </div>
560 </body>
561 </html>