diff --git a/app/client/stylesheets/style.less b/app/client/stylesheets/style.less index e7f56d0..4f1cc57 100644 --- a/app/client/stylesheets/style.less +++ b/app/client/stylesheets/style.less @@ -1,582 +1,581 @@ @import "bootstrap/custom.bootstrap.output.import.less"; @import "theme/flatly.import.less"; @import "x_editable.import.less"; @import "sweetalert.import.less"; @grid-float-breakpoint: 830px; body { padding-top: 60px; } @media print { body { padding-top: 0px; } } td, th { line-height: 1.2; padding-bottom: 0.6em; } table.tight { td, th { padding-bottom: 0; } } table.collapsed { width: inherit; } .reactive-table { th { color: @text-color !important; } td.buttons { text-align: right; } .btn { width: 61px; } .btn-stack { padding: 5.5px 10px; } } .reactive-table-navigation .form-inline input { width: 60px; } .form-control { padding: 3px 5px; } .daterangepicker { color: black; } .page-header, .page-header-small { border-bottom: none; } .nav-tabs { li > form { padding-top: 6px; input:first-child { padding-bottom: 6px; } } /* use a span class=tab instead of "a" */ li span.tab { position: relative; display: block; padding: 10px 15px; line-height: 1.42857143; border: 1px solid transparent; border-radius: 4px 4px 0 0; color: #18bc9c; text-decoration: none; cursor: pointer; &:hover { border-color: #ecf0f1 #ecf0f1 #ecf0f1; text-decoration: none; background-color: #ecf0f1; } } li.active span.tab{ color: #2c3e50; background-color: #ffffff; border: 1px solid #ecf0f1; border-bottom-color: transparent; } } .errors { margin-top: 15px; } //////////////////////////////// // generic .valid { color: @brand-success; } .invalid { color: @brand-warning; alpha: 0.5; } - + //////////////////////////////// // patients .patients { margin-top: 10px; .fa-chevron-right { vertical-align: -29%; } #patientsTable { tr { cursor: pointer; } } } //////////////////////////////// // patient .patient { .profile { overflow: hidden; h4:first-child { margin-top: -8px; } .hrid { font-weight: bold; } .id, .hrid { cursor: pointer; } h5 { font-weight: bold; margin-bottom: 6px; margin-top: 12px; } img { margin-bottom: 10.5px; } } #visits { table { .due{color: @brand-success;} .over-due {color: @brand-warning;} .future {font-style: italic;} .no-date span { font-style: italic; - color: @text-color !important; } .showQuestionnaire { display: inline-block; padding: 0px 15px; line-height: 1.5em; } td:last-child { vertical-align: middle; } } } #visit { .designTitle { cursor: pointer; } .questionnaires { table { width: initial; font-size: 20px; td:not(:first-child) { padding-left: 15px; } td.buttons { min-width: 250px; } } } } } //////////////////////////////// // editQuestionnaire .editQuestionnaire { margin-top: 10px; .markdownControls { display: none; } .question { cursor: pointer; padding: 10px 10px; &:nth-child(even) { background-color: #f5f5f5; } .af-radio-group { margin-left: 7px; .radio-inline, .fix-indent { margin-right: 40px; } } &.selectedQuestion { border: 1px solid @brand-info; border-radius: 2px; //padding: 10px 5px; } } .choice-value, .subquestion-code { input { font-size: 0.8em; padding: 1px 2px; } - } + } #questionEditor { margin-bottom: 20px; .panel > .list-group .list-group-item { padding: 5px 5px 0px 5px; border: 0; } .panel .autoform-add-item { margin-left: 10px; margin-bottom: 5px; } } .buttons-container { height: 60px; padding-right: 15px; } } .translateQuestionnaire { .line { display: flex; &:nth-child(even) { background-color: lightgray; } } .question { width: 50%; } .question-translation{ max-width: 49%; margin-left: 15px; flex-grow: 1; border-left: 1px solid @brand-primary; } .translation-settings { .row { padding: 10px 25px; } .question-translation { padding: 10px 10px; } select { display: inline-block; width: inherit; } } } //////////////////////////////// // questions .question { .control-label { font-weight: bold; } .question-table { td:not(:first-child) { text-align: center; } tr:nth-child(even) { background-color: #ecf0f1; } tr:nth-child(odd).missing-answer { background-color: rgba(231, 76, 60, 0.3) !important; } tr:nth-child(even).missing-answer { background-color: rgba(231, 76, 60, 0.45) !important; } } .question-table-polar { td:not(:first-child):not(:last-child) { text-align: center; } td:last-child { text-align: right; } } .questionAutoform { &.missing-answer { padding: 15px; background-color: rgba(231, 76, 60, 0.3) !important; } } .code { color: @brand-danger; margin-right: 15px; display: inline-block; } } //////////////////////////////// // editStudy #studyPageOverlay { z-index: 1000; //navbar is 1030 cursor: not-allowed; } .editStudyPatients { table tr{ cursor: pointer; } } .editStudyDesigns { .all-questionnaires { .label { font-weight: normal; } } .designs { a { margin: 0px 5px; } } .design { .controls { float: right; margin-right: 15px } } @media print { font-size: 0.8em; .btn-group { display: none; } .controls { display: none; } } .studyDesignTable { .visitTd { border-bottom: 1px solid #dddddd; } .btn-group { min-width: 150px; text-align: right; } td.title { font-weight: bold; white-space: nowrap; span { margin-right: 10px; } } } .bootstrap-tagsinput { width: 90%; input { box-shadow: none; } } // th { // white-space: nowrap; // &:first-child { // width: 250px; // } // &:not(:first-child) { // text-align: center; // } // &:nth-of-type(even):not(:first-child):not(:last-child) { // border-bottom: 2px solid @brand-primary; // } // &:nth-of-type(odd):not(:first-child):not(:last-child) { // border-bottom: 2px dashed @brand-primary; // } // .text-muted { // font-weight: normal; // } // } // td { // &:not(:first-child) { // text-align: center; // } // &:last-child { // width: 200px; // } // } // } } //////////////////////////////// // questionnaireWizzard .questionnaireWizzard { .modal-dialog, .modal-content { margin: 0px; width: 100%; height: 100%; overflow-y: auto; border: none; box-shadow: none; border-radius: 0; .modal-header { background-color: white; position: fixed; width: 100%; height: 75px; z-index: 9999; .title-wrapper { position: fixed; overflow: hidden; h2 { line-height: 1.1; } } .regulations { float: right; td { line-height: 0.9; } } } .modal-body { margin-top: 75px; } } .questionOverview { color: white; i { color: grey; } .active { - .activeCircle { - color: @brand-warning; + .activeCircle { + color: @brand-warning; font-size: 2.5em; top: -4px; left: -1.5px; } } .answered { i { color: @brand-success; } } .answeredPartly { i { color: @brand-info; } } } input[type=radio], input[type="checkbox"] { font-size: 30px; } .nav-buttons { display: flex; flex-direction: row-reverse; justify-content: space-between; } } //////////////////////////////// // export #export { .treeCol { overflow-x: scroll; border-right: 1px solid @brand-primary; } .contentCol { margin-top: 10px; #table { th { white-space: nowrap; //border-right: 1px solid black; padding: 0px 20px 0px 5px; } td { white-space: nowrap; padding: 0px 20px 0px 5px; } } } .btn-danger{ margin-left: 20px; } } //////////////////////////////// // segmentation .row-fill { overflow-y: scroll; -webkit-overflow-scrolling: touch; } .row-max-half { overflow-y: scroll; -webkit-overflow-scrolling: touch; } //////////////////////////////// // misc #spinner { height: 300px; } .label { font-size: 85%; display: inline-block; } .label-warning { background-color: rgba(243, 156, 18, 0.3); } .smallSelect { width: auto; height: auto; padding: 2px 5px; display: inline-block; border: none; margin: 3px 0px; } .smallInput { //height: auto; padding: 2px 5px; display: inline-block; border: none; margin: 3px 0px; } .btn-img { padding: 0; border: none; background: none; &:hover, &:focus, &:active { color: inherit !important; box-shadow: none; } -webkit-box-shadow: none; box-shadow: none; } .cursorPointer { cursor: pointer; } .page-header-small { &:extend(.page-header); margin: 0px; } .btn-hdr { margin-left: 15px; //vertical-align: bottom; } .btn-stack { padding: 5.5px 7px; } .hoverOpaque { opacity: 0.6; &:hover { opacity: 1.0; } } .hoverOpaqueExtreme { opacity: 0.4; &:hover { opacity: 1.0; } } .hoverOpaqueInvisible { opacity: 0.1; &:hover { opacity: 1.0; } } .brand-primary { color: @brand-primary; } .modal-content { background-color: white; } .italic { font-style: italic; } diff --git a/app/client/views/patients/patient_visits.coffee b/app/client/views/patients/patient_visits.coffee index 4ca595e..6b5639d 100644 --- a/app/client/views/patients/patient_visits.coffee +++ b/app/client/views/patients/patient_visits.coffee @@ -1,120 +1,122 @@ Template.patientVisits.destroyed = -> $('.x-editable-meteorized').off 'shown', __editableDateSanitizer Template.patientVisits.rendered = -> #manage selectedPatientStudyDesignId @autorun -> sSDId = Session.get('selectedPatientStudyDesignId') patient = Template.currentData().patient if !patient? or !patient.studyDesignIds? or patient.studyDesignIds.length is 0 return if !sSDId? or patient.studyDesignIds.indexOf(sSDId) < 0 studyDesigns = patient.studyDesigns().fetch() if studyDesigns? and studyDesigns.length > 0 sdId = studyDesigns[0]._id if sdId? Session.set 'selectedPatientStudyDesignId', sdId else Session.set 'selectedPatientStudyDesignId', null return refreshEditableDateSanitizer = -> Meteor.setTimeout -> $('.x-editable-meteorized').on 'shown', __editableDateSanitizer , 100 Template.patientVisits.helpers designs: -> @patient.studyDesigns() designTabClasses: -> if @_id is Session.get('selectedPatientStudyDesignId') "active" else "" + displayDate: (date) -> + if date? + fullDate(date) + else + 'no date set' + + styleDate: (date) -> + if !date? + return "no-date" + date = moment(date) + now = moment() + if date.year() is now.year() and date.dayOfYear() is now.dayOfYear() + return "due" + else if date.isBefore(now) + return "over-due" + else + return "future" + visits: -> patient = @patient studyDesigns = patient.studyDesigns().fetch() selectedPatientStudyDesignId = Session.get 'selectedPatientStudyDesignId' if !studyDesigns? or studyDesigns.length is 0 or !selectedPatientStudyDesignId? return null - visits = __getScheduledVisitsForPatientId(patient._id, selectedPatientStudyDesignId) - now = moment() - visits.forEach (v) -> - date = null - if v.date? - date = moment(v.date) - else if v.dateScheduled? - date = moment(v.dateScheduled) - if !date? - v.dateCSS = "no-date" - else - if date.year() is now.year() and date.dayOfYear() is now.dayOfYear() - v.dateCSS = "due" - else if date.isBefore(now) - v.dateCSS = "over-due" - else - v.dateCSS = "future" - visits + return __getScheduledVisitsForPatientId(patient._id, selectedPatientStudyDesignId) visitDateEO: -> refreshEditableDateSanitizer() visit = @visit patient = @patient - date = visit.date or visit.dateScheduled or null + # date = visit.date or visit.dateScheduled or null + date = visit.date or null dateString = null if date? dateString = fullDate(date) value: dateString emptytext: "no date set" success: (response, newVal) -> if newVal is "-" date = null else date = sanitizeDate(newVal) if !date? return "invalid date" if !visit.designVisitId #we have a template Meteor.call "initVisit", visit._id, patient._id, (error, visitId) -> throwError error if error? Meteor.call "changeVisitDate", visitId, date, (error) -> throwError error if error? else Meteor.call "changeVisitDate", visit._id, date, (error) -> throwError error if error? return #this questionnaire visit patient questionnaireCSS: -> return "valid" if @questionnaire.answered "invalid" - + #this questionnaire visit patient physioRecordsCSS: -> return "valid" if @visit.physioValid "invalid" Template.patientVisits.events "click .switchDesign": (evt) -> Session.set 'selectedPatientStudyDesignId', @_id #with questionnaire visit= patient "click .showQuestionnaire": (evt, tmpl) -> data = questionnaire: @questionnaire visit: @visit patient: @patient readonly: true __showQuestionnaireWizzard data false #this visit patient "click .openVisit": (evt) -> visit = @visit patient = @patient if visit.designVisitId? Session.set 'selectedDesignVisitId', visit.designVisitId else Session.set 'selectedDesignVisitId', visit._id diff --git a/app/client/views/patients/patient_visits.html b/app/client/views/patients/patient_visits.html index f6c596c..577f8b2 100644 --- a/app/client/views/patients/patient_visits.html +++ b/app/client/views/patients/patient_visits.html @@ -1,58 +1,73 @@ <template name="patientVisits"> <div id="designs"> <ul class="nav nav-tabs hidden-print"> {{#each designs}} <li role="presentation" class={{designTabClasses}}> <a href="" class="switchDesign"> {{title}} </a> </li> {{/each}} </ul> </div> <div id="visits"> <table class="table table-striped collapsed"> + <thead> + <tr> + <td> Visit name </td> + <td> Visit date </td> + <td> Date scheduled </td> + <td> Questionnaires </td> + <td></td> + <td></td> + </tr> + </thead> <tbody> {{#each visits}} {{#with visit=this patient=../patient}} <tr> <td class="openVisit cursorPointer"><b>{{visit.title}}</b></td> <td> - <p class={{visit.dateCSS}}>{{> xEditable visitDateEO}}</p> + <p class={{styleDate(visit.date)}}>{{> xEditable visitDateEO}}</p> + </td> + <td> + <p class={{styleDate(visit.dateScheduled)}}> + <span>{{displayDate(visit.dateScheduled)}}</span> + </p> </td> <td> {{#each visit.validatedQuestionnaires}} {{#with questionnaire=. visit=../visit patient=../patient}} <div class="text-center showQuestionnaire {{questionnaireCSS}} cursorPointer"> <i class="fa fa-lg fa-file-text-o"></i> <div> {{questionnaire.id}}<br> {{#if questionnaire.numQuestionsRequired}} {{percentage questionnaire.numQuestionsRequired questionnaire.numAnsweredRequired}} {{else}} 100% {{/if}} </div> </div> {{/with}} {{/each}} </td> <td> {{#if visit.recordPhysicalData}} <i class="fa fa-lg fa-heartbeat {{physioRecordsCSS}}"></i> {{/if}} </td> <td class="openVisit cursorPointer"><i class="fa fa-2x fa-arrow-circle-right"></i></td> </tr> {{/with}} {{else}} <br> This patient either isn't mapped to an study design or this design has no visits scheduled. {{/each}} </tbody> </table> </div> </template>