source: extensions/net.sf.basedb.reggie/trunk/resources/persinfo.jsp @ 1290

Last change on this file since 1290 was 1290, checked in by Nicklas Nordborg, 11 years ago

References #291: Personal information registration

Should now handle the case with an existing patient properly. Depedning on the number of cases already registered the user may create a new case or merge with an existing case.

Display messages after the registration and added a button to restart the wizard for a second registration.

File size: 18.2 KB
Line 
1<%@ page
2  pageEncoding="UTF-8"
3  session="false"
4  import="net.sf.basedb.core.Application"
5  import="net.sf.basedb.core.User"
6  import="net.sf.basedb.core.DbControl"
7  import="net.sf.basedb.core.SessionControl"
8  import="net.sf.basedb.clients.web.Base"
9  import="net.sf.basedb.clients.web.util.HTML"
10  import="net.sf.basedb.util.Values"
11%>
12<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
13<%@ taglib prefix="p" uri="/WEB-INF/path.tld" %>
14<%
15final SessionControl sc = Base.getExistingSessionControl(request, true);
16final String ID = sc.getId();
17final float scale = Base.getScale(sc);
18DbControl dc = null;
19try
20{
21  dc = sc.newDbControl();
22  final User user = User.getById(dc, sc.getLoggedInUserId());
23%>
24<base:page type="default" >
25<base:head scripts="ajax.js" styles="path.css">
26<script language="JavaScript">
27
28var currentStep = 1;
29var pnrIsValid = false;
30var caseIsValid = false;
31
32var patientInfo = null;
33var caseInfo = null;
34
35function goNext()
36{
37  if (currentStep == 1)
38  {
39    if (pnrIsValid && caseIsValid) gotoStep2();
40  }
41  else if (currentStep == 2)
42  {
43    gotoStep3();
44  }
45}
46
47function caseNameOnChange()
48{
49  var frm = document.forms['reggie'];
50  var caseName = frm.caseName.value;
51  if (caseName == '')
52  {
53    setInputStatus('case', 'Missing', 'invalid');
54    return;
55  }
56  setInputStatus('case', '', 'valid');
57  caseIsValid = true;
58}
59
60function personalNumberOnChange()
61{
62  var frm = document.forms['reggie'];
63  var pnr = frm.personalNumber.value;
64  pnrIsValid = false;
65 
66  if (pnr.length < 12)
67  {
68    setInputStatus('pnr', 'Too short', 'invalid');
69    return;
70  }
71 
72  if (!Dates.isDate(pnr.substring(0, 8), 'yyyyMMdd'))
73  {
74    setInputStatus('pnr', 'Not a valid date', 'invalid');
75    return;
76  }
77 
78  var sum = 0;
79  var factor = 2;
80  var x = '';
81  for (var i = 2; i < 11; i++)
82  {
83    var digit = parseInt(pnr.substr(i, 1));
84    var tmp = factor * digit;
85    x += '(' + factor + '*' + digit+')';
86    sum += tmp >= 10 ? tmp - 9: tmp;
87    factor = factor == 2 ? 1 : 2;
88  }
89 
90  var control = 10 - (sum % 10);
91  if (control != parseInt(pnr.substr(11, 1)))
92  {
93    setInputStatus('pnr', 'Invalid control digit', 'invalid');
94    return;
95  }
96 
97  setInputStatus('pnr', '', 'valid');
98  pnrIsValid = true;
99 
100  //if (caseIsValid) gotoStep2();
101}
102
103function lateralityOnChange()
104{
105  // Check selected laterality against specimen tubes
106  var frm = document.forms['reggie'];
107  var selectedLaterality = Forms.getCheckedRadio(frm.laterality);
108 
109  // No laterality/case selected
110  if (selectedLaterality == null) return;
111 
112  var laterality = selectedLaterality.value;
113  if (laterality != 'LEFT' && laterality != 'RIGHT')
114  {
115    // It is the ID of an existing case
116    for (var i = 0; i < patientInfo.cases.length; i++)
117    {
118      var cse = patientInfo.cases[i];
119      if (cse.id == laterality)
120      {
121        laterality = cse.laterality;
122        break;
123      }
124    }
125  }
126 
127  if (!laterality) return;
128 
129  // No specimen tubes
130  if (!caseInfo.specimen || caseInfo.specimen.length == 0) return;
131 
132  for (var i = 0; i < caseInfo.specimen.length; i++)
133  {
134    var specimen = caseInfo.specimen[i];
135    if (specimen.laterality && specimen.laterality != laterality)
136    {
137      setInputStatus('laterality', 'Not same laterality as specimen tubes', 'warning');
138      return;
139    }
140  }
141  setInputStatus('laterality', '', 'valid');
142}
143
144function goNextOnTab(event)
145{
146  if (event.keyCode == 9) setTimeout('goNext()', 200);
147  return true;
148}
149
150function gotoStep2()
151{
152  // Check entered case and pnr with AJAX
153  var frm = document.forms['reggie'];
154  frm.caseName.disabled = true;
155  frm.personalNumber.disabled = true;
156  currentStep = 2;
157 
158  var pnr = frm.personalNumber.value;
159  var caseName = frm.caseName.value;
160  var request = Ajax.getXmlHttpRequest();
161  var url = 'PersonalRegistration.servlet?ID=<%=ID%>&cmd=CheckPersonalNumberAndCaseName';
162  url += '&personalNumber=' + pnr;
163  url += '&caseName=' + caseName;
164  request.open("GET", url, false);
165  request.send(null);
166 
167  setInnerHTML('debug', request.responseText);
168 
169  var response = JSON.parse(request.responseText);
170  if (response.status != 'ok')
171  {
172    setFatalError(response.message);
173    return false;
174  }
175 
176  // Get biosource information from the AJAX response
177  patientInfo = response.patientInfo;
178  caseInfo = response.caseInfo;
179 
180  if (!patientInfo.id)
181  {
182    Main.show('newPatientSection');
183    frm.patientCode.value=patientInfo.name;
184    setInnerHTML('new.dateOfBirth', patientInfo.dateOfBirth);
185    setInnerHTML('new.gender', patientInfo.gender);
186    frm.familyName.focus();
187  }
188  else
189  {
190    Main.show('existingPatientSection');
191    setInnerHTML('existing.patientCode', patientInfo.name);
192    setInnerHTML('existing.familyName', patientInfo.familyName);
193    setInnerHTML('existing.allFirstNames', patientInfo.allFirstNames);
194    setInnerHTML('existing.dateOfBirth', patientInfo.dateOfBirth);
195    setInnerHTML('existing.gender', patientInfo.gender);
196    gotoStep3();
197  }
198}
199
200function gotoStep3()
201{
202  // Check entered case and pnr with AJAX
203  var frm = document.forms['reggie'];
204
205  if (!patientInfo.id)
206  {
207    var formOk = true;
208    // Validate 'New patient' form
209    if (frm.allFirstNames.value == '')
210    {
211      setInputStatus('allFirstNames', 'Missing', 'invalid');
212      frm.allFirstNames.focus();
213      formOk = false;
214    }
215    else
216    {
217      setInputStatus('allFirstNames', '', 'valid');
218    }
219   
220    if (frm.familyName.value == '')
221    {
222      setInputStatus('familyName', 'Missing', 'invalid');
223      frm.familyName.focus();
224      formOk = false;
225    }
226    else
227    {
228      setInputStatus('familyName', '', 'valid');
229    }
230
231   
232    if (frm.patientCode.value == '')
233    {
234      setInputStatus('patientCode', 'Missing', 'invalid');
235      frm.patientCode.focus();
236      formOk = false;
237    }
238    else
239    {
240      setInputStatus('patientCode', '', 'valid');
241    } 
242    if (!formOk) return;
243  }
244 
245  currentStep = 3;
246  if (!patientInfo.id)
247  {
248    frm.patientCode.disabled = true;
249    frm.familyName.disabled = true;
250    frm.allFirstNames.disabled = true;
251    patientInfo.familyName = frm.familyName.value;
252    patientInfo.allFirstNames = frm.allFirstNames.value;
253  }
254 
255  // Generate list of specimen tubes
256  var thisCaseLaterality;
257  if (caseInfo.specimen && caseInfo.specimen.length > 0)
258  {
259    var specimenTubes = '';
260    Main.hide('reasonIfNoSpecimenSection');
261    for (var i = 0; i < caseInfo.specimen.length; i++)
262    {
263      var specimen = caseInfo.specimen[i];
264      specimenTubes += specimen.name ;
265      if (specimen.laterality) 
266      {
267        specimenTubes += ' ('+specimen.laterality + ')';
268        Forms.checkRadio(frm.laterality, specimen.laterality);
269       
270        if (thisCaseLaterality && thisCaseLaterality != specimen.laterality)
271        {
272          setInputStatus('specimenTubes', 'Specimen tubes with different laterality', 'warning');
273        }
274        thisCaseLaterality = specimen.laterality;
275      }
276      specimenTubes += '<br>';
277    }
278    setInnerHTML('specimenTubes', specimenTubes);
279  }
280
281 
282  Main.show('caseSection');
283 
284  // Existing cases for this patient
285  var hasLeftCase = false;
286  var hasRightCase = false;
287  if (patientInfo.cases && patientInfo.cases.length > 0)
288  {
289    var cases = '';
290    for (var i = 0; i < patientInfo.cases.length; i++)
291    {
292      var cc = patientInfo.cases[i];
293      cases += '<input type="radio" name="laterality" value="' + cc.id + '"';
294      if (cc.laterality == 'LEFT') 
295      {
296        if (hasLeftCase) setInputStatus('laterality', 'Two cases with LEFT', 'warning');
297        hasLeftCase = true;
298      }
299      if (cc.laterality == 'RIGHT') 
300      {
301        if (hasRightCase) setInputStatus('laterality', 'Two cases with RIGHT', 'warning');
302        hasRightCase = true;
303      }
304      if (cc.laterality == thisCaseLaterality) cases += ' checked';
305      cases += ' onclick="lateralityOnChange()">';
306      cases += cc.name + ' (' + cc.laterality + ')<br>';
307    }
308   
309    if (!hasLeftCase)
310    {
311      cases += '<input type="radio" name="laterality" value="LEFT" ';
312      if (thisCaseLaterality == 'LEFT') cases += ' checked';
313      cases += ' onclick="lateralityOnChange()"><i>new case</i> (LEFT)<br>';
314    }
315    if (!hasRightCase)
316    {
317      cases += '<input type="radio" name="laterality" value="RIGHT"';
318      if (thisCaseLaterality == 'RIGHT') cases += ' checked';
319      cases += ' onclick="lateralityOnChange()"><i>new case</i> (RIGHT)<br>';
320    }
321   
322    if (hasLeftCase && hasRightCase)
323    {
324      setInnerHTML('laterality.prompt', 'Merge with case');
325    }
326    else
327    {
328      setInnerHTML('laterality.prompt', 'Merge/create new case');
329    }
330   
331    setInnerHTML('laterality.input', cases);
332  }
333  lateralityOnChange();
334
335  Main.hide('gonext');
336  Main.show('gocreate');
337}
338
339function goCreate()
340{
341  Main.hide('gocreate');
342  var frm = document.forms['reggie'];
343
344  caseInfo.laterality = Forms.getCheckedRadio(frm.laterality).value;
345  caseInfo.reasonIfNoSpecimen = frm.reasonIfNoSpecimen.value;
346 
347  var submitInfo = new Object();
348  submitInfo.patientInfo = patientInfo;
349  submitInfo.caseInfo = caseInfo;
350
351  var request = Ajax.getXmlHttpRequest();
352  var url = 'PersonalRegistration.servlet?ID=<%=ID%>&cmd=Create';
353  request.open("POST", url, false);
354  request.setRequestHeader("Content-Type", "application/json");
355  request.send(JSON.stringify(submitInfo));
356
357  setInnerHTML('debug', request.responseText);
358 
359  var response = JSON.parse(request.responseText);
360  if (response.status != 'ok')
361  {
362    setFatalError(response.message);
363    return false;
364  }
365 
366  var msg = '<ul>';
367  for (var i = 0; i < response.messages.length; i++)
368  {
369    msg += '<li>' + response.messages[i];
370  }
371  msg += '</ul>';
372  setInnerHTML('done', msg);
373  Main.show('done');
374  Main.show('gorestart');
375
376}
377
378
379function setInnerHTML(id, html)
380{
381  var tag = document.getElementById(id);
382  if (!tag) alert('No tag with id='+id);
383  tag.innerHTML = html;
384}
385
386function setInputStatus(prefix, message, clazz)
387{
388  var tag = document.getElementById(prefix + '.status');
389  tag.className = 'status ' + clazz;
390 
391  setInnerHTML(prefix + '.message', message);
392  if (message)
393  {
394    Main.showInline(prefix + '.message');
395  }
396  else
397  {
398    Main.hide(prefix + '.message');
399  }
400}
401
402function setFatalError(message)
403{
404  setInnerHTML('errorMessage', message);
405  Main.show('errorMessage');
406  Main.hide('gonext');
407  Main.show('gorestart');
408}
409
410function goRestart()
411{
412  location.href = location.href;
413}
414</script>
415<style>
416
417.stepform
418{
419  margin-left: 20px;
420  border: 1px solid #999999;
421  width: 800px;
422  table-layout: fixed;
423}
424
425.stepno
426{
427  width: 20px;
428  font-size: 20px;
429  font-weight: bold;
430  color: #E0E0E0;
431  background: #555577;
432  vertical-align: top;
433  text-align: center;
434}
435
436.steptitle
437{
438  width: 780px;
439  color: #333377;
440  background: #E0E0E0;
441  font-weight: bold;
442  padding: 1px 4px 1px 4px;
443  border-bottom: 1px solid #999999;
444}
445
446.nextstep
447{
448  width: 780px;
449  color: #333377;
450  background: #E0E0E0;
451  font-weight: bold;
452  padding: 1px 4px 1px 4px;
453  border-top: 1px solid #999999;
454}
455
456.stepfields
457{
458  width: 780px;
459}
460
461.prompt
462{
463  width: 150px;
464  font-weight: bold;
465  padding: 1px 2px 1px 2px;
466}
467
468.input
469{
470  width: 250px;
471  padding: 1px 2px 1px 2px;
472}
473
474.status
475{
476  width: 30px;
477  padding: 1px 2px 1px 2px;
478}
479
480.help
481{
482  background: #e0e0e0;
483  width: 350px;
484  font-style: italic;
485  padding: 1px 2px 1px 2px;
486}
487
488.message
489{
490  color: #cc0000;
491  font-weight: bold;
492  padding-right: 6px;
493}
494
495.status.invalid:before
496{
497  content: url('../../images/error.gif');
498}
499.status.warning:before
500{
501  content: url('../../images/warning.gif');
502}
503.status.valid:before
504{
505  content: url('../../images/ok.gif');
506}
507.success ul
508{
509  list-style-image: url('../../images/ok.gif');
510}
511</style>
512</base:head>
513<base:body>
514
515  <p:path style="margin-top: 20px; margin-bottom: 10px;">
516    <p:pathelement title="Reggie" href="<%="index.jsp?ID="+ID%>" />
517    <p:pathelement title="Personal information registration" />
518  </p:path>
519
520  <form name="reggie" onsubmit="return false;">
521 
522  <!-- 1. Case + Personal number -->
523  <table border="0" cellspacing="0" cellpadding="0" class="stepform">
524  <tr>
525    <td rowspan="3" class="stepno">1</td>
526    <td class="steptitle">Enter Case Name and Personal Number</td>
527  </tr>
528  <tr>
529    <td class="stepfields">
530      <table border="0" cellspacing="0" cellpadding="0" width="100%">
531      <tr valign="top">
532        <td class="prompt">Case name</td>
533        <td class="input"><input type="text" name="caseName" 
534          size="18" maxlength="12" onblur="caseNameOnChange()"></td>
535        <td class="status" id="case.status"></td>
536        <td class="help"><span id="case.message" class="message" style="display: none;"></span>The case (barcode) associated with this patient.</td>
537      </tr>
538      <tr>
539        <td class="prompt">Personal number</td>
540        <td class="input"><input type="text" name="personalNumber" 
541          size="18" maxlength="12" onkeyup="personalNumberOnChange()" onkeypress="goNextOnTab(event)"></td>
542        <td class="status" id="pnr.status"></td>
543        <td class="help"><span id="pnr.message" class="message" style="display: none;"></span>(YYYYMMDDZZZZ)</td>
544      </tr>
545      </table>
546    </td>
547  </tr>
548  </table>
549
550  <!-- 2. New patient registration -->
551  <div id="newPatientSection" style="display: none;">
552  <p>
553  <table border="0" cellspacing="0" cellpadding="0" class="stepform">
554  <tr>
555    <td rowspan="2" class="stepno">2</td>
556    <td class="steptitle">New patient: Enter all names</td>
557  </tr>
558  <tr>
559    <td class="stepfields">
560      <table border="0" cellspacing="0" cellpadding="0" width="100%">
561      <tr>
562        <td class="prompt">Patient code</td>
563        <td class="input"><input type="text" name="patientCode" value="" size="18" maxlength="12"></td>
564        <td class="status" id="patientCode.status"></td>
565        <td class="help"><span id="patientCode.message" class="message" style="display: none;"></span></td>
566      </tr>
567      <tr valign="top">
568        <td class="prompt">Family name</td>
569        <td class="input"><input type="text" name="familyName" 
570          size="35" maxlength="255"></td>
571        <td class="status" id="familyName.status"></td>
572        <td class="help"><span id="familyName.message" class="message" style="display: none;"></span>Keep hyphens, keep åäö, replace all special accented letters [e.g. éèü etc] with standard alphabet character.</td>
573      </tr>
574      <tr valign="top">
575        <td class="prompt">All first names</td>
576        <td class="input"><input type="text" name="allFirstNames" 
577          size="35" maxlength="255" onkeypress="goNextOnTab(event)"></td>
578        <td class="status" id="allFirstNames.status"></td>
579        <td class="help"><span id="allFirstNames.message" class="message" style="display: none;"></span>Type all names, see FamilyName comment on valid characters.</td>
580      </tr>
581      <tr>
582        <td class="prompt">Gender</td>
583        <td class="input" id="new.gender"></td>
584        <td class="status"></td>
585        <td class="help"></td>
586      </tr>
587      <tr>
588        <td class="prompt">Date of birth</td>
589        <td class="input" id="new.dateOfBirth"></td>
590        <td class="status"></td>
591        <td class="help"></td>
592      </tr>
593      </table>
594    </td>
595  </tr>
596  </table>
597  </div>
598 
599  <!-- 2b. Existing patient -->
600  <div id="existingPatientSection" style="display: none;">
601  <p>
602  <table border="0" cellspacing="0" cellpadding="0" class="stepform">
603  <tr>
604    <td rowspan="2" class="stepno">2</td>
605    <td class="steptitle">Existing patient: Verify names</td>
606  </tr>
607  <tr>
608    <td class="stepfields">
609      <table border="0" cellspacing="0" cellpadding="0" width="100%">
610      <tr>
611        <td class="prompt">Patient code</td>
612        <td class="input" id="existing.patientCode"></td>
613        <td class="status"></td>
614        <td class="help"></td>
615      </tr>
616      <tr>
617        <td class="prompt">Family name</td>
618        <td class="input" id="existing.familyName"></td>
619        <td class="status"></td>
620        <td class="help"></td>
621      </tr>
622      <tr>
623        <td class="prompt">All first names</td>
624        <td class="input" id="existing.allFirstNames"></td>
625        <td class="status"></td>
626        <td class="help"></td>
627      </tr>
628      <tr>
629        <td class="prompt">Gender</td>
630        <td class="input" id="existing.gender"></td>
631        <td class="status"></td>
632        <td class="help"></td>
633      </tr>
634      <tr>
635        <td class="prompt">Date of birth</td>
636        <td class="input" id="existing.dateOfBirth"></td>
637        <td class="status"></td>
638        <td class="help"></td>
639      </tr>
640      </table>
641    </td>
642  </tr>
643  </table>
644  </div>
645
646
647  <!-- 3. Case registration -->
648  <div id="caseSection" style="display: none;">
649  <p>
650  <table border="0" cellspacing="0" cellpadding="0" class="stepform">
651  <tr>
652    <td rowspan="2" class="stepno">3</td>
653    <td class="steptitle">About this case</td>
654  </tr>
655  <tr>
656    <td class="stepfields">
657      <table border="0" cellspacing="0" cellpadding="0" width="100%">
658      <tr valign="top">
659        <td class="prompt" id="laterality.prompt">Laterality</td>
660        <td class="input" id="laterality.input">
661          <input type="radio" name="laterality" value="LEFT" onclick="lateralityOnChange()">LEFT
662          <input type="radio" name="laterality" value="RIGHT" onclick="lateralityOnChange()">RIGHT
663        </td>
664        <td class="status" id="laterality.status"></td>
665        <td class="help"><span id="laterality.message" class="message" style="display: none;"></span></td>
666      </tr>
667      <tr valign="top">
668        <td class="prompt">Specimen tubes</td>
669        <td class="input" id="specimenTubes"><i>not found</i></td>
670        <td class="status" id="specimenTubes.status"></td>
671        <td class="help"><span id="specimenTubes.message" class="message" style="display: none;"></span>The specimen tube(s) associated with this case.</td>
672      </tr>
673      <tr id="reasonIfNoSpecimenSection" valign="top">
674        <td class="prompt">Reason if no specimen</td>
675        <td class="input"><textarea rows="3" cols="30" name="reasonIfNoSpecimen" value=""></textarea></td>
676        <td class="status"></td>
677        <td class="help">Comment why there was no specimen tubes in the delivery.</td>
678      </tr>
679      </table>
680    </td>
681  </tr>
682  </table>
683  </div>
684
685  <div class="error" id="errorMessage" style="display: none; width: 800px; margin-left: 20px; margin-bottom: 0px;"></div>
686
687  <div id="done" class="success" style="display: none; width: 800px; margin-left: 20px; margin-top: 20px;"></div>
688
689  <table style="margin-left: 20px; margin-top: 10px;">
690    <tr><td><base:button id="gonext" title="Next" image="gonext.gif" onclick="goNext()"/></td></tr>
691    <tr><td><base:button id="gocreate" title="Create" image="gonext.gif" onclick="goCreate()" style="display: none;"/></td></tr>
692    <tr><td><base:button id="gorestart" title="Restart" image="goback.gif" onclick="goRestart()" style="display: none;"/></td></tr>
693  </table>
694  </form>
695
696  <pre>
697  <div id="debug"></div>
698  </pre>
699 
700</base:body>
701</base:page>
702<%
703}
704finally
705{
706  if (dc != null) dc.close();
707}
708%>
Note: See TracBrowser for help on using the repository browser.