diff --git a/Makefile b/Makefile index f907d04118..4f9d0a6a1c 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,7 @@ db_create_test: # docker-compose run --no-deps -e RAILS_ENV=test --entrypoint "rake db:drop" app docker-compose run --no-deps -e RAILS_ENV=test --entrypoint "rake db:create" app docker-compose run --no-deps -e RAILS_ENV=test --entrypoint "rake db:schema:load" app + # docker exec -it mongo mongo --authenticationDatabase admin --host localhost -u mongo -p 123456789 oscar_history_test --eval "db.dropUser('oscar'); db.createUser({user: 'oscar', pwd: '123456789', roles: [{role: 'readWrite', db: 'oscar_history_test'}]});" docker-compose exec -T mongo mongo --authenticationDatabase admin --host localhost -u mongo -p 123456789 oscar_history_test --eval "db.dropUser('oscar'); db.createUser({user: 'oscar', pwd: '123456789', roles: [{role: 'readWrite', db: 'oscar_history_test'}]});" # If the container is NOT running and you want to get a bash terminal then run this command diff --git a/app/assets/images/cb_dmat/1-5-years.png b/app/assets/images/cb_dmat/1-5-years.png new file mode 100755 index 0000000000..e6daaa5c55 Binary files /dev/null and b/app/assets/images/cb_dmat/1-5-years.png differ diff --git a/app/assets/images/cb_dmat/1-year.png b/app/assets/images/cb_dmat/1-year.png new file mode 100755 index 0000000000..ec10e41b5e Binary files /dev/null and b/app/assets/images/cb_dmat/1-year.png differ diff --git a/app/assets/images/cb_dmat/12-months.png b/app/assets/images/cb_dmat/12-months.png new file mode 100755 index 0000000000..7c2b6dc0e3 Binary files /dev/null and b/app/assets/images/cb_dmat/12-months.png differ diff --git a/app/assets/images/cb_dmat/18-months.png b/app/assets/images/cb_dmat/18-months.png new file mode 100755 index 0000000000..989f4d60ca Binary files /dev/null and b/app/assets/images/cb_dmat/18-months.png differ diff --git a/app/assets/images/cb_dmat/2-5-years.png b/app/assets/images/cb_dmat/2-5-years.png new file mode 100755 index 0000000000..215438da80 Binary files /dev/null and b/app/assets/images/cb_dmat/2-5-years.png differ diff --git a/app/assets/images/cb_dmat/2-years.png b/app/assets/images/cb_dmat/2-years.png new file mode 100755 index 0000000000..f858bd79cb Binary files /dev/null and b/app/assets/images/cb_dmat/2-years.png differ diff --git a/app/assets/images/cb_dmat/3-months.png b/app/assets/images/cb_dmat/3-months.png new file mode 100755 index 0000000000..c6e90b319e Binary files /dev/null and b/app/assets/images/cb_dmat/3-months.png differ diff --git a/app/assets/images/cb_dmat/3-years.png b/app/assets/images/cb_dmat/3-years.png new file mode 100755 index 0000000000..04c36e138b Binary files /dev/null and b/app/assets/images/cb_dmat/3-years.png differ diff --git a/app/assets/images/cb_dmat/4-years.png b/app/assets/images/cb_dmat/4-years.png new file mode 100755 index 0000000000..cf578d81ab Binary files /dev/null and b/app/assets/images/cb_dmat/4-years.png differ diff --git a/app/assets/images/cb_dmat/5-years.png b/app/assets/images/cb_dmat/5-years.png new file mode 100755 index 0000000000..b5a346b8d3 Binary files /dev/null and b/app/assets/images/cb_dmat/5-years.png differ diff --git a/app/assets/images/cb_dmat/6-months.png b/app/assets/images/cb_dmat/6-months.png new file mode 100755 index 0000000000..08279bf0a2 Binary files /dev/null and b/app/assets/images/cb_dmat/6-months.png differ diff --git a/app/assets/images/cb_dmat/6-years.png b/app/assets/images/cb_dmat/6-years.png new file mode 100755 index 0000000000..cf578d81ab Binary files /dev/null and b/app/assets/images/cb_dmat/6-years.png differ diff --git a/app/assets/images/cb_dmat/9-months.png b/app/assets/images/cb_dmat/9-months.png new file mode 100755 index 0000000000..e6daaa5c55 Binary files /dev/null and b/app/assets/images/cb_dmat/9-months.png differ diff --git a/app/assets/javascripts/advanced_filter_builder.coffee b/app/assets/javascripts/advanced_filter_builder.coffee index ddd5792b05..131937fe6e 100644 --- a/app/assets/javascripts/advanced_filter_builder.coffee +++ b/app/assets/javascripts/advanced_filter_builder.coffee @@ -14,6 +14,7 @@ class CIF.AdvancedFilterBuilder window.customGroup["#{addRule.id}"] = addRule if window.customGroup["#{addRule.id}"] == undefined $('#builder_group_0').find('.rules-group-body .btn-custom-group').hide() + $('#builder_group_0').find('.rules-group-body .btn-default-group').hide() $(@element.selector).on 'beforeDeleteGroup.queryBuilder', (parent, group) -> if $('body#clients-index').length diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 8de48b902a..b517172cd4 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -128,6 +128,7 @@ //= require settings/research_module //= require settings/client_forms //= require settings/integration +//= require settings/risk_assessment //= require settings/customize_case_note //= require prevent_required_file_uploader //= require format_special_characters @@ -148,3 +149,4 @@ //= require case_conferences/form //= require internal_referrals/form //= require service_receives/form +//= require screening_assessments/form diff --git a/app/assets/javascripts/application_with_pack.js b/app/assets/javascripts/application_with_pack.js new file mode 100644 index 0000000000..9b3f02faae --- /dev/null +++ b/app/assets/javascripts/application_with_pack.js @@ -0,0 +1,62 @@ +// FRAMEWORK +//= require jquery +//= require jquery_ujs +//= require jquery-ui +//= require bootstrap-sprockets +//= require jquery.steps.min +//= require jquery.validate +//= require jquery.validate.additional-methods +//= require jquery.nicescroll.min + +//= require editable/bootstrap-editable +//= require editable/rails +//= require jQuery.print + +//= require image_upload_previewer/image_upload_previewer +//= require image_upload +//= require bootstrap-datepicker/core +//= require bootstrap-datepicker/locales/bootstrap-datepicker.en-GB.js +//= require datepicker +//= require metisMenu/jquery.metisMenu.js +//= require lodash/lodash.min.js +// require query_builder/query-builder.standalone.min.js +//= require jquery.extendext +//= require doT +//= require query-builder + +//remove query_builder/utils, query_builder/model and query_builder/plugin bcuz conflict with form-builder select option not show + +//= require moment +//= require fullcalendar +//= require bootstrap_file_input/purify.min.js +//= require bootstrap_file_input/fileinput.js +//= require bootstrap_file_input/fa/theme.min.js +//= require bootstrap_file_input/explorer/theme.min.js + +// WRAPBOOTSTRAP +//= require iCheck/icheck.min.js +//= require wrapbootstrap/inspinia.js +//= require slimscroll/jquery.slimscroll.min.js +//= require toastr/toastr.min.js +//= require bootstrap-tour/bootstrap-tour.js + +// LADDA +//= require ladda/spin.min +//= require ladda/ladda.min +//= require ladda/ladda.jquery.min + +//LOAD MODULE +//= require namespace +//= require util +//= require initializer +//= require common +//= require jquery.infinitescroll.min +//= require footable.all.min + +//APPLICATION JS +//= require calendars/index +//= require clients/index +//= require report_creator +//= require clients/show +//= require clients/form +//= require clients/book diff --git a/app/assets/javascripts/assessments/form.coffee b/app/assets/javascripts/assessments/form.coffee index 78f952832f..7c8bfad766 100644 --- a/app/assets/javascripts/assessments/form.coffee +++ b/app/assets/javascripts/assessments/form.coffee @@ -1,5 +1,6 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.AssessmentsUpdate = do -> _init = -> + window.domainOptionScores = {} forms = $('form.assessment-form') for form in forms @@ -73,7 +74,7 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen currentTabLabels = $(@).siblings() currentTabLabels.removeClass('active-label') - + domainOptionScores[@.dataset.domainId] = @.dataset.score $('.score_option').removeClass('is_error') labelColors = 'btn-danger btn-warning btn-primary btn-success btn-secondary' currentTabLabels.removeClass(labelColors) @@ -85,6 +86,7 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen $($(@).siblings().get(-1)).val(score) $('.score_option input').attr('required','required') + $('.col-xs-12').on 'click', '.score_option label', -> return if $(@).closest(".root-wizard").attr("id") == 'readonly-rootwizard' @@ -149,7 +151,7 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen currentTab = "#{rootId}-p-#{currentIndex}" domainId = $("#{currentTab}").find('.score_option').data('domain-id') - return true if _disableRequiredFields() || rootId == '#readonly-rootwizard' + return true if _disableRequiredFields() || rootId == '#readonly-rootwizard' || domainId == undefined form.validate().settings.ignore = ':disabled,:hidden' form.valid() @@ -167,7 +169,8 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen _formEdit(rootId, currentIndex) $('a#btn-save').show() - if currentStep.hasClass('domain-last') or $(rootId).find('a[href="#finish"]:visible').length + if (currentStep.hasClass('domain-last') or $(rootId).find('a[href="#finish"]:visible').length) + _setTotalRiskAssessment() if $(rootId).find('a[href="#finish"]:visible').length console.log 'hiding save button' $("#{rootId} a[href='#save']").hide() @@ -179,9 +182,7 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen form.validate().settings.ignore = ':disabled' form.valid() - currentStep = $("#{rootId}-p-" + currentIndex) - - _filedsValidator(currentIndex,newIndex) + _filedsValidator(currentIndex, newIndex) onFinished: -> return if rootId == '#readonly-rootwizard' @@ -191,6 +192,20 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen $('.actions a:contains("Done")').removeAttr('href') form.submit() + _setTotalRiskAssessment = -> + scoreColors = $('.score_option.with-def')[0].dataset + total = 0 + $.each $('.risk-assessment-domain-score'), (index, element) -> + scoreValue = domainOptionScores[element.dataset.domainId] + if !_.isEmpty(domainOptionScores) && scoreValue + color = scoreColors["score-#{scoreValue}"] + $(element).addClass("btn-#{color || 'primary'}") + $(element).html(scoreValue) + total += parseInt($(element).html()) + + total = Math.round(parseFloat(total) / $('.risk-assessment-domain-score').length) + $('#btn-total').html(total) if total != 0 + _appendSaveButton = -> if $('#rootwizard').find('a[href="#finish"]:visible').length == 0 && $("#btn-save").length == 0 $('#rootwizard').find("[aria-label=Pagination]").append("
  • ") @@ -227,36 +242,38 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen scoreOption = $("#{currentTab} .score_option.without-def") chosenScore = scoreOption.find('label input:checked').val() - scoreColor = scoreOption.data("score-#{chosenScore}") - scoreOption.find("label label:contains(#{chosenScore})").addClass("label-default active-label") - - btnScore = scoreOption.find('input:hidden').val() - $(scoreOption.find("div[data-score='#{btnScore}']").get(0)).addClass("btn-secondary") - domainName = $(@).data('goal-option') - name = 'assessment[assessment_domains_attributes]['+ "#{currentIndex}" +'][goal_required]\']' - radioName = '\'' + name - goalRequiredValue = $("input[name=#{radioName}:checked").val() - select = $(currentTab).find('textarea.goal') - - if scoreColor == 'primary' - if goalRequiredValue == 'false' - $(select).val('') - $(select).prop('readonly', true) - $(select).addClass('valid') - else if goalRequiredValue == 'true' - $(select).prop('readonly', false) - $(select).removeClass('valid') - $(select).addClass('valid') if $(select).val() != '' - else - if $(select).val() != '' - $(select).addClass('valid') + if chosenScore + scoreColor = scoreOption.data("score-#{chosenScore}") + scoreOption.find("label label:contains(#{chosenScore})").addClass("label-default active-label") + + btnScore = scoreOption.find('input:hidden').val() + $(scoreOption.find("div[data-score='#{btnScore}']").get(0)).addClass("btn-secondary") + domainName = $(@).data('goal-option') + name = 'assessment[assessment_domains_attributes]['+ "#{currentIndex}" +'][goal_required]\']' + radioName = '\'' + name + goalRequiredValue = $("input[name=#{radioName}:checked").val() + select = $(currentTab).find('textarea.goal') + + if scoreColor == 'primary' + if goalRequiredValue == 'false' + $(select).val('') + $(select).prop('readonly', true) + $(select).addClass('valid') + else if goalRequiredValue == 'true' + $(select).prop('readonly', false) + $(select).removeClass('valid') + $(select).addClass('valid') if $(select).val() != '' else - $(select).removeClass('valid').addClass('required') + if $(select).val() != '' + $(select).addClass('valid') + else + $(select).removeClass('valid').addClass('required') _filedsValidator = (currentIndex, newIndex ) -> - return true if _disableRequiredFields() - currentTab = "#rootwizard-p-#{currentIndex}" + + return true if _disableRequiredFields() || $("#{currentTab}.domain-client-wellbeing-score").length + scoreOption = $("#{currentTab} .score_option") reason = $("#{currentTab} .reason").val() return false unless reason diff --git a/app/assets/javascripts/client_advance_search.coffee b/app/assets/javascripts/client_advance_search.coffee index 845bfe4db5..429f566e5d 100644 --- a/app/assets/javascripts/client_advance_search.coffee +++ b/app/assets/javascripts/client_advance_search.coffee @@ -3,6 +3,7 @@ class CIF.ClientAdvanceSearch @filterTranslation = '' @customFormSelected = [] @programSelected = [] + @assessmentSelected = '' optionTranslation = $('#opt-group-translation') @enrollmentCheckbox = $('#enrollment-checkbox') @@ -16,6 +17,7 @@ class CIF.ClientAdvanceSearch @ENROLLMENT_URL = '/api/client_advanced_searches/get_enrollment_field' @TRACKING_URL = '/api/client_advanced_searches/get_tracking_field' @EXIT_PROGRAM_URL = '/api/client_advanced_searches/get_exit_program_field' + @PROGRAM_STREAM_URL = '/api/client_advanced_searches/get_program_stream_search_field' @DOMAIN_SCORES_TRANSLATE = $(optionTranslation).data('csiDomainScores') @BASIC_FIELD_TRANSLATE = $(optionTranslation).data('basicFields') @@ -34,6 +36,7 @@ class CIF.ClientAdvanceSearch setValueToBuilderSelected: -> @customFormSelected = $('#custom-form-data').data('value') @programSelected = $('#program-stream-data').data('value') + @assessmentSelected = $('#assessment-form-data').data('value') @wizardCustomFormSelected = $('#wizard-custom-form-data').data('value') @wizardProgramSelected = $('#wizard-program-stream-data').data('value') @@ -92,11 +95,11 @@ class CIF.ClientAdvanceSearch initSelect2: -> - $('#custom-form-select, #wizard-custom-form-select, #program-stream-select, #wizard-program-stream-select, #quantitative-case-select').select2() + $('#custom-form-select, #wizard-custom-form-select, #program-stream-select, #wizard-program-stream-select, #quantitative-case-select, #assessment-select').select2() $('#builder select').select2() $('#wizard-builder select').select2() setTimeout ( -> - ids = ['#custom-form-select', '#wizard-custom-form-select', '#program-stream-select', '#wizard-program-stream-select', '#quantitative-case-select', '#wizard-builder', '#builder'] + ids = ['#custom-form-select', '#wizard-custom-form-select', '#program-stream-select', '#wizard-program-stream-select', '#quantitative-case-select', '#wizard-builder', '#builder', '#assessment-select'] $.each ids, (index, item) -> $("#{item} .rule-filter-container select").select2(width: '250px') $("#{item} .rule-operator-container select, .rule-value-container select").select2(width: 'resolve') @@ -119,6 +122,7 @@ class CIF.ClientAdvanceSearch wizardBasicQueryRules = $('#wizard-builder').data('basic-search-rules') unless basicQueryRules == undefined or _.isEmpty(basicQueryRules.rules) self.handleAddHotlineFilter() + console.log(basicQueryRules, 'basic query') $('#builder').queryBuilder('setRules', basicQueryRules) unless wizardBasicQueryRules == undefined or _.isEmpty(wizardBasicQueryRules.rules) $('#wizard-builder').queryBuilder('setRules', wizardBasicQueryRules) @@ -147,6 +151,11 @@ class CIF.ClientAdvanceSearch $('#custom-form-column').removeClass('hidden') $('#wizard-custom-form .loader').addClass('hidden') + assessmentSelectChange: -> + self = @ + $('.main-report-builder .assessment-form-wrapper select').on 'select2-selecting', (element) -> + self.assessmentSelected = element.val + addCustomBuildersFields: (ids, url, loader=undefined) -> self = @ action = _.last(url.split('/')) @@ -231,6 +240,36 @@ class CIF.ClientAdvanceSearch $('#custom-form-checkbox').on 'ifChecked', -> $('.custom-form').show() + handleHideAssessmentSelect: -> + self = @ + $('#assessment-checkbox').on 'ifUnchecked', -> + ruleFiltersSelect = $('.main-report-builder .rule-container .rule-filter-container select') + ruleFiltersSelect.select2('destroy') + ruleFiltersSelect.parents('.rule-container').find('.rule-header button').trigger('click') + self.assessmentSelected = '' + $('.assessment-form').hide() + $('#builder').queryBuilder('removeFilter', ['assessment_condition_last_two','assessment_condition_first_last']) + $('button[data-add="rule"]').trigger('click') + self.initSelect2() + return + + handleShowAssessmentSelect: -> + self = @ + if $('#assessment-checkbox').prop('checked') + $('.assessment-form').show() + $('#assessment-checkbox').on 'ifChecked', -> + $('.assessment-form').show() + self.assessmentSelected = $('select.assessment-select').val() + $.ajax + url: self.PROGRAM_STREAM_URL + data: { assesment_checked: true } + method: 'GET' + success: (response) -> + fieldList = response.client_advanced_searches + $('#builder').queryBuilder('addFilter', fieldList) + self.initSelect2() + return + ###################################################################################################################### customFormSelectRemove: -> @@ -258,6 +297,19 @@ class CIF.ClientAdvanceSearch if $('#wizard_custom_form_filter').is(':checked') self.handleRemoveFilterBuilder(removeValue, self.CUSTOM_FORM_TRANSLATE, '#wizard-builder') + assessmentSelectRemove: -> + self = @ + $('.main-report-builder .assessment-form-wrapper select').on 'select2-removed', (element) -> + $.map self.assessmentSelected, (val, i) -> + if parseInt(val) == parseInt(element.val) then self.assessmentSelected.splice(i, 1) + + removeActiveClientProgramOption: -> + $('.main-report-builder .rule-container .rule-filter-container select').select2('destroy') + $('.main-report-builder .rule-container').find('.rule-header button').trigger('click') + $('button[data-add="rule"]').trigger('click') + $('#builder').queryBuilder('removeFilter', ['active_client_program']) + @.initSelect2() + handleRemoveFilterBuilder: (resourceName, resourcelabel, elementBuilder = '#builder') -> self = @ if elementBuilder == '#builder' @@ -323,6 +375,7 @@ class CIF.ClientAdvanceSearch $('.main-report-builder .program-association, .main-report-builder .program-stream').hide() $('.main-report-builder .program-association input[type="checkbox"]').iCheck('uncheck') $('.main-report-builder select.program-stream-select').select2("val", "") + self.removeActiveClientProgramOption() handleProgramSelectChange: -> self = @ @@ -330,6 +383,9 @@ class CIF.ClientAdvanceSearch programId = psElement.val self.programSelected.push programId $('.main-report-builder .program-association').show() + if self.programSelected.length == 1 + self.addCustomBuildersFields(self.programSelected, self.PROGRAM_STREAM_URL, self.LOADER) + if $('#enrollment-checkbox').is(':checked') self.LOADER.start() self.addCustomBuildersFields(programId, self.ENROLLMENT_URL, self.LOADER) @@ -679,6 +735,9 @@ class CIF.ClientAdvanceSearch programStreamAssociation = $('.main-report-builder .program-association') $(programStreamAssociation).find('.i-checks').iCheck('uncheck') $(programStreamAssociation).hide() + + if self.programSelected.length == 0 + self.removeActiveClientProgramOption() $('#report-builder-wizard .program-stream-select').on 'select2-removed', (element) -> programName = element.choice.text @@ -808,6 +867,7 @@ class CIF.ClientAdvanceSearch builderForm = '.main-report-builder' programValues = if self.programSelected.length > 0 then "[#{self.programSelected}]" customFormValues = if self.customFormSelected.length > 0 then "[#{self.customFormSelected}]" + assessmentValues = if self.assessmentSelected.length > 0 then "[#{self.assessmentSelected}]" else builderElement = '#wizard-builder' builderForm = '#report-builder-wizard' @@ -823,6 +883,7 @@ class CIF.ClientAdvanceSearch self.setValueToProgramAssociation() $('#client_advanced_search_custom_form_selected').val(customFormValues) $('#client_advanced_search_program_selected').val(programValues) + $('#client_advanced_search_assessment_selected').val(assessmentValues) if $('#quantitative-type-checkbox').prop('checked') then $('#client_advanced_search_quantitative_check').val(1) if $('#wizard_quantitative_filter').prop('checked') then $('#client_advanced_search_wizard_quantitative_check').val(1) if $('#wizard_custom_form_filter').prop('checked') then $('#client_advanced_search_wizard_custom_form_check').val(1) diff --git a/app/assets/javascripts/clients/index.coffee b/app/assets/javascripts/clients/index.coffee index 81572ed8c4..8893923be4 100644 --- a/app/assets/javascripts/clients/index.coffee +++ b/app/assets/javascripts/clients/index.coffee @@ -58,10 +58,31 @@ CIF.ClientsIndex = do -> _addTourTip(tour) _extendDataTableSort() _addDataTableToAssessmentScoreData() + _addDataTableToTableSummary() _removeReferralDataColumnsInWizardClientColumn() _handleShowCustomFormSelect() _reOrderRuleContainer() _initHelpTextPophover() + _initClientColumnFilter() + + _initClientColumnFilter = -> + searchBox = $('.client-column ul.columns-visibility #column-search-box') + searchBox.keyup -> + valThis = $(this).val().toLowerCase() + if valThis == '' + $('.client-column ul.columns-visibility > li').show() + else + $('.client-column ul.columns-visibility > li:not(:first-child)').each -> + text = $(this).text().toLowerCase() + if text.indexOf(valThis) >= 0 then $(this).show() else $(this).hide() + return + return + + $('.client-column ul.columns-visibility .btn-clear-text').click -> + searchBox.val '' + searchBox.focus() + $('.client-column ul.columns-visibility > li').show() + return _reOrderRuleContainer = -> $.each $('.csi-group .rules-list'), (index, item)-> @@ -93,12 +114,20 @@ CIF.ClientsIndex = do -> _addDataTableToAssessmentScoreData = -> fileName = $('.assessment-domain-score').data('filename') - _handleAjaxRequestToAssessment("#csi-assessment-score", fileName) - _handleAjaxRequestToAssessment("#custom-assessment-score", fileName) if $("#custom-assessment-score") + _handleAjaxRequestToAssessment("#csi-assessment-score", fileName) if $("#csi-assessment-score").length + _handleAjaxRequestToAssessment("#custom-assessment-score", fileName) if $("#custom-assessment-score").length $('.assessment-domain-score').on 'shown.bs.modal', (e) -> $($.fn.dataTable.tables(true)).DataTable().columns.adjust() return + _addDataTableToTableSummary = -> + fileName = $('.table-summary').data('filename') + _handleDataTable("#table-summary-age", fileName) + _handleDataTable("#table-summary-referral-category", fileName) + $('.table-summary').on 'shown.bs.modal', (e) -> + $($.fn.dataTable.tables(true)).DataTable().columns.adjust() + return + _handleAjaxRequestToAssessment = (tableId, fileName)-> url = $("#{tableId} .api-assessment-path").data('assessment-params') columns = $("#{tableId} .assessment-domain-headers").data('headers') @@ -109,7 +138,10 @@ CIF.ClientsIndex = do -> processing: true serverSide: true sServerMethod: 'POST' - ajax: url + ajax: + url: url + error: (jqXHR, textStatus, errorThrown) -> + console.log("Datatable Ajax Error:", errorThrown) oLanguage: { sProcessing: "" } @@ -143,6 +175,35 @@ CIF.ClientsIndex = do -> $(tableId).css 'width': '100%' return + _handleDataTable = (tableId, fileName)-> + table = $(tableId).DataTable + autoWidth:true + bFilter: false + bPaginate: false + info: false + ordering: false + processing: true + oLanguage: { + sProcessing: "" + } + scrollX: true + dom: 'lBrtip' + buttons: [{ + filename: fileName + extend: 'excelHtml5' + customize: ( xlsx ) -> + sheet = xlsx.xl.worksheets['sheet1.xml'] + $('row:last c:first', sheet).attr('s', '2') + text: ' Excel Export' + exportOptions: modifier: + search: 'applied' + order: 'applied' + }], + 'drawCallback': (oSettings) -> + $('.dataTables_scrollHeadInner').css 'width': '100%' + $(tableId).css 'width': '100%' + return + _handleShowCustomFormSelect = -> if $('#wizard-referral-data .referral-data-column .i-checks').is(':checked') $('#wizard-referral-data').show() @@ -182,6 +243,7 @@ CIF.ClientsIndex = do -> onInit: -> $('ul[role="tablist"]').hide() + $('ul.table-summary-tab[role="tablist"]').show() $('.actions a[href="#finish"]').attr('id', 'wizard-search') _handleReportBuilderWizardDisplayBtns() _handleQueryFilters('#wizard_custom_form_filter', '#wizard-custom-form-select') @@ -435,6 +497,8 @@ CIF.ClientsIndex = do -> advanceFilter.customFormSelectChange() advanceFilter.customFormSelectRemove() advanceFilter.handleHideCustomFormSelect() + advanceFilter.assessmentSelectChange() + advanceFilter.assessmentSelectRemove() advanceFilter.handleShowProgramStreamFilter() advanceFilter.handleHideProgramStreamSelect() @@ -473,6 +537,9 @@ CIF.ClientsIndex = do -> advanceFilter.removeOperatorInWizardBuilder() advanceFilter.handleHotlineFilter() + advanceFilter.handleShowAssessmentSelect() + advanceFilter.handleHideAssessmentSelect() + _handleColumnVisibilityParams = -> $('button#search').on 'click', -> allCheckboxes = $('#client-search-form, #client-advance-search-wizard').find('#new_client_grid ul input[type=checkbox]') diff --git a/app/assets/javascripts/screening_assessments/form.coffee b/app/assets/javascripts/screening_assessments/form.coffee new file mode 100644 index 0000000000..41fae46ff1 --- /dev/null +++ b/app/assets/javascripts/screening_assessments/form.coffee @@ -0,0 +1,69 @@ +CIF.Screening_assessmentsNew = CIF.Screening_assessmentsCreate = CIF.Screening_assessmentsUpdate = CIF.Screening_assessmentsEdit = do -> + _init = -> + _handleMileStoneAgeSelect() + _initDatePicker() + _cocoonCallback() + _handleCheckBox() + _handleFormSubmitting() + + _handleMileStoneAgeSelect = -> + mileStoneAge = $('#screening_assessment_client_milestone_age').val() + _removeClassFieldSet(mileStoneAge) + + $('#screening_assessment_client_milestone_age').on 'change', -> + $('fieldset').addClass('hidden') + $('fieldset input[type="hidden"]').val('true') + + value = @.value + _removeClassFieldSet(value) + + _removeClassFieldSet = (value)-> + _handleCheckBox() + $("fieldset[data-developmental-marker-screening-assessment-name='#{value}']").removeClass('hidden') + $("fieldset[data-developmental-marker-screening-assessment-name='#{value}'] input").removeAttr('disabled') + $("fieldset[data-developmental-marker-screening-assessment-name='#{value}'] input[type='hidden']").val('false') + + _initDatePicker = -> + $('.date-picker').datepicker + autoclose: true, + format: 'yyyy-mm-dd', + todayHighlight: true, + disableTouchKeyboard: true, + startDate: '1899,01,01', + todayBtn: true, + .attr('readonly', 'true').css('background-color','#ffffff').keypress (e) -> + if e.keyCode == 8 + e.preventDefault() + return + + _cocoonCallback = -> + $('#tasks').on 'cocoon:after-insert', -> + _initDatePicker() + + _handleCheckBox = -> + $('#tasks').removeClass('hide') unless _.every(_isInputRadioAllChecked()) + + $(document).on 'change', 'fieldset input:radio:visible', (event) -> + if !eval(event.target.value) + $('#tasks').removeClass('hide') + else + $('#tasks').addClass('hide') if _.every(_isInputRadioAllChecked()) + + _isInputRadioAllChecked = -> + nameAttributes = $('fieldset input:radio:visible').map( -> + $(this).prop('name') + ).get() + + nameValue = _.uniq(nameAttributes).map (element) -> + "input:radio[name='" + element + "']" + + nameValue.map (value) -> + $(value).prop('checked') + + _handleFormSubmitting = -> + $("form#screening-assessment").on 'submit', (e)-> + e.preventDefault() + $("#tasks .nested-fields .row").remove() if _.every(_isInputRadioAllChecked()) + @.submit() + + { init: _init } diff --git a/app/assets/javascripts/settings/risk_assessment.coffee b/app/assets/javascripts/settings/risk_assessment.coffee new file mode 100644 index 0000000000..f21656f936 --- /dev/null +++ b/app/assets/javascripts/settings/risk_assessment.coffee @@ -0,0 +1,53 @@ +CIF.SettingsRisk_assessment = do -> + _init = -> + _initICheckBox() + _handleSettingAssessmentTypeNameChange() + _tinyMCE() + + _initICheckBox = -> + if $('#setting_enabled_risk_assessment').is(':checked') + $('#assessment-type-name').show() + $('#guidance').show() + else + $(".domain-checkbox-wrapper").hide() + $('#assessment-type-name').hide() + $('#guidance').hide() + + $('.i-checks').iCheck( + checkboxClass: 'icheckbox_square-green' + radioClass: 'iradio_square-green' + ).on('ifChecked', -> + $('#assessment-type-name').show() + $('#guidance').show() + _showHideDomainCheckBox($('#setting_assessment_type_name:visible').val()) + ).on 'ifUnchecked', -> + return if @.id.match(/setting_selected_domain_ids/) && @.id.match(/setting_selected_domain_ids/).length + + $(".domain-checkbox-wrapper").hide() + $('#assessment-type-name').hide() + $('#guidance').hide() + + _handleSettingAssessmentTypeNameChange = -> + $(".domain-checkbox-wrapper").hide() + _showHideDomainCheckBox($('#setting_assessment_type_name:visible').val()) + $('#setting_assessment_type_name').on 'change', (e) -> + $(".domain-checkbox-wrapper").hide() + _showHideDomainCheckBox(e.target.value) + + _showHideDomainCheckBox = (value) -> + if value == 'csi' + $("##{value}").show() + else + $("#custom-domain-#{value}").show() + + return + + _tinyMCE = -> + tinymce.init + selector: 'textarea.tinymce' + plugins: 'lists' + width : '100%' + toolbar: 'bold italic numlist bullist' + menubar: false + + { init: _init } diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 17269cfafc..0c52bc604a 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -97,4 +97,6 @@ @import "care_plans/*"; @import "family_advanced_searches/*"; @import "service_deliveries/*"; -@import "case_conferences/*"; \ No newline at end of file +@import "case_conferences/*"; +@import "datatable/*"; +@import "screening_assessments/form"; diff --git a/app/assets/stylesheets/assessments/form.scss b/app/assets/stylesheets/assessments/form.scss index c2de7579c4..6738b3db0c 100644 --- a/app/assets/stylesheets/assessments/form.scss +++ b/app/assets/stylesheets/assessments/form.scss @@ -1,4 +1,5 @@ -.wizard, .tabcontrol { +.wizard, +.tabcontrol { overflow: initial; } @@ -7,7 +8,9 @@ body[id='assessments-create'], body[id='assessments-edit'], body[id='assessments-update'] { #readonly-rootwizard { - textarea.disabled, textarea:disabled { + + textarea.disabled, + textarea:disabled { color: black !important; } } @@ -44,34 +47,43 @@ body[id='assessments-update'] { .steps { display: none; } + .content { background-color: #fff; margin: 0; + .body { width: 100%; padding: 0; + label { margin-bottom: 0; } + input { display: inline-block; } } } + .actions { padding: 20px 0; } } - .margin-title{ + + .margin-title { margin-left: 10px; } - .button{ + + .button { width: 110px; } + .assessment-domain-item { span { margin-left: 30px; margin-right: 30px; + input { margin-right: 10px; } @@ -85,81 +97,102 @@ body[id='assessments-update'] { } } } - #rootwizard{ - .content{ + + #rootwizard { + .content { height: auto; } } - .tasks-list{ + + .tasks-list { margin-top: 16px; padding: 0px; } - ol li.list-group-item{ + + ol li.list-group-item { list-style: decimal inside; display: list-item; } + .assessment_assessment_domains_reason { margin-top: 5px; + textarea { height: 120px; } } + .well { max-height: 400px; overflow: scroll; ul { margin-left: 25px; + li { line-height: 30px; } } } - .wizard > .actions .disabled a{ + .wizard>.actions .disabled a { border: 1px solid #acb3ac; border-radius: 3px; text-align: center; display: inline; } - .wizard > .actions a{ + + .wizard>.actions a { text-align: center; display: inline; border-radius: 3px; } + .wrap-text-style { white-space: normal; text-align: center; } - .score_option.is_error{ + + .score_option.is_error { border: 1px solid #a94442; border-radius: 2px; } + .score_option { border: 1px solid #fff; padding: 8px 3px 8px 3px; - span{ + + span { padding: 0 20px 0 0; } - em{ + + em { display: none !important; } + text-align: center; - label, input { - display:block-inline; + + label, + input { + display: block-inline; } + input[type="radio"] { - opacity:0.011; - z-index:100; + opacity: 0.011; + z-index: 100; } - input[type="radio"]:checked + label { + + input[type="radio"]:checked+label { color: #fff; } - input[type="radio"]:checked + em + label { + + input[type="radio"]:checked+em+label { color: #fff; } - label{ + + label { font-size: 16px; + .collection_radio_buttons { padding: 8px; border: 1px solid #CCC; @@ -169,21 +202,26 @@ body[id='assessments-update'] { height: 40px; border-radius: 5px; } + label:hover { - background:#DDD; + background: #DDD; } } } - textarea.error{ + + textarea.error { border: 1px solid #a94442; } - em.error{ + + em.error { color: #a94442; font-size: 14px; font-weight: normal; - padding:3px; - text-align:left;; + padding: 3px; + text-align: left; + ; } + .padding-bottom { padding-bottom: 140px; } @@ -193,11 +231,12 @@ body[id='assessments-update'] { padding: 15px; } - @media only screen and (max-device-width : 767px){ + @media only screen and (max-device-width : 767px) { .assessment-domain-item { span { margin-left: 0; margin-right: 0; + input { margin-right: 10px; } @@ -211,14 +250,18 @@ body[id='assessments-update'] { } } } + .score_option { padding: 8px 0 8px 0; - span{ + + span { padding: 0 0 0 0; } } } - .links img, .nested-fields img { + + .links img, + .nested-fields img { width: 150px; cursor: pointer; } @@ -232,14 +275,15 @@ body[id='assessments-update'] { width: 150px; } - .image-title{ + .image-title { width: 70%; } - .table.attachment-table tbody>tr>td{ + .table.attachment-table tbody>tr>td { vertical-align: top; } - .table.attachment-table tbody>tr>td.vert-align{ + + .table.attachment-table tbody>tr>td.vert-align { vertical-align: middle; } @@ -247,8 +291,10 @@ body[id='assessments-update'] { border: 1px solid #999999; } - .goal-required-option, .task-required-option { + .goal-required-option, + .task-required-option { display: inline; + span { display: inline-block; margin-right: 20px; @@ -269,9 +315,8 @@ body[id='assessments-update'] { display: inline-flex; align-items: center; } - .tasks-list { - } + .tasks-list {} } } @@ -280,3 +325,8 @@ body[id='assessments-update'] { margin-right: 5px; } } + +.domai-name-score-wrapper { + display: flex; + align-items: center; +} diff --git a/app/assets/stylesheets/case_notes/form.scss b/app/assets/stylesheets/case_notes/form.scss index 2c45b68ace..bf7ae99493 100644 --- a/app/assets/stylesheets/case_notes/form.scss +++ b/app/assets/stylesheets/case_notes/form.scss @@ -112,6 +112,10 @@ body[id=case_notes-create] { } .panel-heading .popover-content { - color: black !important + color: black !important; + + label.boolean { + font-weight: bold; + } } } diff --git a/app/assets/stylesheets/case_notes/index.scss b/app/assets/stylesheets/case_notes/index.scss index ce8ae44672..809d27317f 100644 --- a/app/assets/stylesheets/case_notes/index.scss +++ b/app/assets/stylesheets/case_notes/index.scss @@ -49,4 +49,12 @@ body[id='case_notes-index'] { margin-bottom: 5px; } } + + .accordion-toggle .glyphicon { + transition: .3s transform ease-in-out; + } + + .accordion-toggle.collapsed .glyphicon { + transform: rotate(-450deg); + } } diff --git a/app/assets/stylesheets/client_advanced_searches/index.scss b/app/assets/stylesheets/client_advanced_searches/index.scss index c0100f4351..8c5996cbaa 100644 --- a/app/assets/stylesheets/client_advanced_searches/index.scss +++ b/app/assets/stylesheets/client_advanced_searches/index.scss @@ -58,7 +58,7 @@ body[id='client_advanced_searches-index'] { display: none; } - .custom-form, .program-stream, .selected-custom-form, .program-association { + .custom-form, .program-stream, .selected-custom-form, .program-association, .assessment-form { display: none; } diff --git a/app/assets/stylesheets/clients/client_grid.scss b/app/assets/stylesheets/clients/client_grid.scss index f506cfc9f3..3798543e34 100644 --- a/app/assets/stylesheets/clients/client_grid.scss +++ b/app/assets/stylesheets/clients/client_grid.scss @@ -248,11 +248,14 @@ body[id="client_advanced_searches-index"] { } ul.check-columns-visibility { padding-left: 0; + li:first-child { + padding: 0 8px 15px 8px; + } li { list-style: none; } .columns-visibility { - height: 250px; + max-height: 250px; width: 390px; overflow-y: scroll; padding-top: 10px; diff --git a/app/assets/stylesheets/clients/form.scss b/app/assets/stylesheets/clients/form.scss index c6da20e2fa..4c6c9bac67 100644 --- a/app/assets/stylesheets/clients/form.scss +++ b/app/assets/stylesheets/clients/form.scss @@ -1,15 +1,25 @@ -body[id='clients-new'], body[id='clients-create'], -body[id='clients-edit'], body[id='clients-update']{ - .wizard > .content > .body { - #getting_started, #living_detail, #other_detail, #specific_point { +body[id='clients-new'], +body[id='clients-create'], +body[id='clients-edit'], +body[id='clients-update'] { + .wizard>.content>.body { + + #getting_started, + #living_detail, + #other_detail, + #specific_point { position: relative; + input[type='radio'] { display: inline-block; } } } - .wizard > .actions a[href="#finish"], .wizard > .actions a[href="#finish"]:hover, .wizard > .actions a[href="#finish"]:active { - background: #1ab394; + + .wizard>.actions a[href="#finish"], + .wizard>.actions a[href="#finish"]:hover, + .wizard>.actions a[href="#finish"]:active { + background: #1ab394; } .remove-files-wrapper { @@ -32,6 +42,7 @@ body[id='clients-edit'], body[id='clients-update']{ .content.clearfix { background-color: inherit; + section { padding: 0; width: 100%; @@ -42,7 +53,7 @@ body[id='clients-edit'], body[id='clients-update']{ margin-top: 30px; } - .icheckbox_square-green{ + .icheckbox_square-green { margin-right: 10px; } @@ -52,9 +63,11 @@ body[id='clients-edit'], body[id='clients-update']{ display: inline-block; margin-right: 20px; } + label { - padding-left: 0; + padding-left: 0; } + .iradio_square-green { margin-right: 5px; } @@ -63,20 +76,25 @@ body[id='clients-edit'], body[id='clients-update']{ .disabled { color: #333 !important; } - .input-group-addon.what3words{ + + .input-group-addon.what3words { padding: 2px; } - .what3words-image{ + + .what3words-image { height: 17%; } - .save-edit-client{ + + .save-edit-client { margin-top: -67px; } - .cancel-client-button{ + + .cancel-client-button { position: relative; } - .consent-forms, .house_number { + .consent-forms, + .house_number { clear: both; } @@ -85,15 +103,18 @@ body[id='clients-edit'], body[id='clients-update']{ pointer-events: none; cursor: not-allowed; } - .warning-message{ + + .warning-message { text-align: left; font-weight: bold; } - .ref-source-cat-reminder{ + + .ref-source-cat-reminder { color: red; } - #step-2, #step-4 { + #step-2, + #step-5 { display: none; } } @@ -102,7 +123,7 @@ body[id='clients-edit'], body[id='clients-update']{ margin-bottom: 5px; } -#family-option{ +#family-option { margin-top: 10px; margin-left: 12px; } @@ -119,37 +140,46 @@ body[id='clients-edit'], body[id='clients-update']{ height: 0; overflow: hidden; z-index: 999999; - &:after, &:before { + + &:after, + &:before { box-sizing: border-box; display: none; } + &.is-active { background-color: rgba(0, 0, 0, 0.85); width: 100%; height: 100%; left: 0; top: 0; - &:after, &:before { + + &:after, + &:before { display: block; } } + &[data-text]:before { position: fixed; left: 0; top: 50%; color: currentColor; - font-family: Helvetica,Arial,sans-serif; + font-family: Helvetica, Arial, sans-serif; text-align: center; width: 100%; font-size: 14px; } + &[data-text=""]:before { content: "Loading"; } + &[data-text] { &:not([data-text=""]):before { content: attr(data-text); } + &[data-blink]:before { animation: blink 1s linear infinite alternate; } @@ -182,6 +212,7 @@ body[id='clients-edit'], body[id='clients-update']{ &[data-text]:before { top: calc(50% - 63px); } + &:after { content: ""; position: fixed; @@ -194,22 +225,27 @@ body[id='clients-edit'], body[id='clients-update']{ left: calc(50% - 24px); animation: rotation 1s linear infinite; } + &[data-half]:after { border-right-color: transparent; } + &[data-inverse]:after { animation-direction: reverse; } } .loader-double { - &:after, &:before { + + &:after, + &:before { content: ""; position: fixed; border-radius: 50%; border: 8px solid; animation: rotation 1s linear infinite; } + &:after { width: 48px; height: 48px; @@ -218,6 +254,7 @@ body[id='clients-edit'], body[id='clients-update']{ top: calc(50% - 24px); left: calc(50% - 24px); } + &:before { width: 64px; height: 64px; @@ -234,6 +271,7 @@ body[id='clients-edit'], body[id='clients-update']{ top: calc(50% - 40px); color: #1ab394; } + &:after { content: ""; position: fixed; @@ -247,9 +285,11 @@ body[id='clients-edit'], body[id='clients-update']{ box-shadow: inset 0 10px 0 hsla(0, 0%, 100%, 0.2), 0 0 0 5px rgba(0, 0, 0, 0.2); animation: moveBar 1.5s linear infinite reverse; } + &[data-rounded]:after { border-radius: 15px; } + &[data-inverse]:after { animation-direction: normal; } @@ -271,22 +311,27 @@ body[id='clients-edit'], body[id='clients-update']{ width: 200px; background-color: #000; } - &:after, &:before { + + &:after, + &:before { content: ""; height: 20px; position: absolute; top: calc(50% - 10px); left: calc(50% - 100px); } + &:after { width: 50px; background-color: #f19; animation: moveBarPingPong .5s linear infinite alternate; } + &[data-rounded] { &:before { border-radius: 10px; } + &:after { border-radius: 50%; width: 20px; @@ -360,6 +405,7 @@ body[id='clients-edit'], body[id='clients-update']{ &[data-text]:before { color: #1ab394; } + &:after { content: ""; position: absolute; @@ -386,9 +432,11 @@ body[id='clients-edit'], body[id='clients-update']{ z-index: 1; animation: kickBall 1s infinite alternate ease-in both; } + &[data-shadow]:before { box-shadow: inset -5px -5px 10px 0 rgba(0, 0, 0, 0.5); } + &:after { content: ""; position: absolute; @@ -448,7 +496,7 @@ body[id='clients-edit'], body[id='clients-update']{ content: ""; color: #fff; font-size: 12px; - font-family: Helvetica,Arial,sans-serif; + font-family: Helvetica, Arial, sans-serif; text-align: center; line-height: 120px; position: fixed; @@ -463,9 +511,11 @@ body[id='clients-edit'], body[id='clients-update']{ background: radial-gradient(circle at 50% 90%, rgba(0, 0, 0, 0.5) 6px, transparent 0), linear-gradient(0deg, #fd0 22px, transparent 0), linear-gradient(0deg, rgba(0, 0, 0, 0.5) 22px, rgba(0, 0, 0, 0.5)); animation: shake 2s cubic-bezier(0.36, 0.07, 0.19, 0.97) both infinite; } + &[data-screen=""]:after { content: "Loading"; } + &:not([data-screen=""]):after { content: attr(data-screen); } @@ -525,16 +575,19 @@ body[id='clients-edit'], body[id='clients-update']{ border-radius: 50%; margin: -60px 0 0 -60px; background: linear-gradient(180deg, transparent 50%, #f5f5f5 0), linear-gradient(90deg, transparent 55px, #2ecc71 0, #2ecc71 65px, transparent 0), linear-gradient(180deg, #f5f5f5 50%, #f5f5f5 0); - box-shadow: inset 0 0 0 10px #f5f5f5,0 0 0 5px #555,0 0 0 10px #7b7b7b; + box-shadow: inset 0 0 0 10px #f5f5f5, 0 0 0 5px #555, 0 0 0 10px #7b7b7b; animation: rotation infinite 2s linear; } - &:after, &:before { + + &:after, + &:before { content: ""; position: fixed; left: 50%; top: 50%; overflow: hidden; } + &:after { width: 60px; height: 40px; @@ -554,11 +607,12 @@ body[id='clients-edit'], body[id='clients-update']{ margin-top: -35px; font-size: 70px; text-align: center; - font-family: Helvetica,Arial,sans-serif; + font-family: Helvetica, Arial, sans-serif; overflow: hidden; line-height: 1.2; content: "Loading"; } + &:before { position: fixed; width: 100%; @@ -566,36 +620,44 @@ body[id='clients-edit'], body[id='clients-update']{ margin-top: -35px; font-size: 70px; text-align: center; - font-family: Helvetica,Arial,sans-serif; + font-family: Helvetica, Arial, sans-serif; overflow: hidden; line-height: 1.2; content: "Loading"; color: #666; } + &:after { color: #fff; height: 0; animation: curtain 1s linear infinite alternate both; } + &[data-curtain-text]:not([data-curtain-text=""]) { - &:after, &:before { + + &:after, + &:before { content: attr(data-curtain-text); } } + &[data-brazilian] { &:before { color: #f1c40f; } + &:after { color: #2ecc71; } } + &[data-colorful] { &:before { animation: maskColorful 2s linear infinite alternate both; } + &:after { - animation: curtain 1s linear infinite alternate both,maskColorful-front 2s 1s linear infinite alternate both; + animation: curtain 1s linear infinite alternate both, maskColorful-front 2s 1s linear infinite alternate both; color: #000; } } @@ -651,7 +713,9 @@ body[id='clients-edit'], body[id='clients-update']{ .loader-music { - &:after, &:before { + + &:after, + &:before { content: ""; position: fixed; width: 240px; @@ -664,59 +728,70 @@ body[id='clients-edit'], body[id='clients-update']{ line-height: 240px; color: #fff; font-size: 40px; - font-family: Helvetica,Arial,sans-serif; + font-family: Helvetica, Arial, sans-serif; text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.5); letter-spacing: -1px; } + &:after { backface-visibility: hidden; } + &[data-hey-oh] { &:after { box-shadow: 0 0 0 10px; } + &:before { box-shadow: 0 0 0 10px; background-color: #fff; color: #000; - animation: coinBack 2.5s linear infinite,oh 5s 1.25s linear infinite both; + animation: coinBack 2.5s linear infinite, oh 5s 1.25s linear infinite both; } + &:after { background-color: #000; - animation: coin 2.5s linear infinite,hey 5s linear infinite both; + animation: coin 2.5s linear infinite, hey 5s linear infinite both; } } + &[data-no-cry] { &:after { background: linear-gradient(45deg, #009b3a 50%, #fed100 51%); box-shadow: 0 0 0 10px #000; } + &:before { background: linear-gradient(45deg, #009b3a 50%, #fed100 51%); box-shadow: 0 0 0 10px #000; - animation: coinBack 2.5s linear infinite,cry 5s 1.25s linear infinite both; + animation: coinBack 2.5s linear infinite, cry 5s 1.25s linear infinite both; } + &:after { - animation: coin 2.5s linear infinite,no 5s linear infinite both; + animation: coin 2.5s linear infinite, no 5s linear infinite both; } } + &[data-we-are] { &:before { - animation: coinBack 2.5s linear infinite,theWorld 5s 1.25s linear infinite both; + animation: coinBack 2.5s linear infinite, theWorld 5s 1.25s linear infinite both; background: radial-gradient(ellipse at center, #4ecdc4 0, #556270); } + &:after { - animation: coin 2.5s linear infinite,weAre 5s linear infinite both; + animation: coin 2.5s linear infinite, weAre 5s linear infinite both; background: radial-gradient(ellipse at center, #26d0ce 0, #1a2980); } } + &[data-rock-you] { &:before { - animation: coinBack 2.5s linear infinite,rockYou 5s 1.25s linear infinite both; + animation: coinBack 2.5s linear infinite, rockYou 5s 1.25s linear infinite both; background: #444; } + &:after { - animation: coin 2.5s linear infinite,weWill 5s linear infinite both; + animation: coin 2.5s linear infinite, weWill 5s linear infinite both; background: #96281b; } } @@ -880,6 +955,7 @@ body[id='clients-edit'], body[id='clients-update']{ z-index: 1; animation: movePokeball 1s linear infinite both; } + &:after { content: ""; position: absolute; @@ -891,9 +967,9 @@ body[id='clients-edit'], body[id='clients-update']{ background-color: #fff; border-radius: 50%; z-index: 2; - animation: movePokeball 1s linear infinite both,flashPokeball .5s infinite alternate; + animation: movePokeball 1s linear infinite both, flashPokeball .5s infinite alternate; border: 2px solid #000; - box-shadow: 0 0 0 5px #fff,0 0 0 10px #000; + box-shadow: 0 0 0 5px #fff, 0 0 0 10px #000; } } @@ -928,7 +1004,9 @@ body[id='clients-edit'], body[id='clients-update']{ .loader-bouncing { - &:after, &:before { + + &:after, + &:before { content: ""; width: 20px; height: 20px; @@ -939,10 +1017,12 @@ body[id='clients-edit'], body[id='clients-update']{ background-color: #fff; animation: kick .6s infinite alternate; } + &:after { margin-left: -30px; animation: kick .6s infinite alternate; } + &:before { animation-delay: .2s; } @@ -960,13 +1040,15 @@ body[id='clients-edit'], body[id='clients-update']{ } } -body[id='clients-new'] .disabled, body[id='clients-create'] .disabled, -body[id='clients-edit'] .disabled, body[id='clients-update'] .disabled { +body[id='clients-new'] .disabled, +body[id='clients-create'] .disabled, +body[id='clients-edit'] .disabled, +body[id='clients-update'] .disabled { color: #fff !important; pointer-events: none; } -#client-confirmation{ +#client-confirmation { .modal-dialog { width: 100%; margin: 0 auto; @@ -978,7 +1060,8 @@ body[id='clients-edit'] .disabled, body[id='clients-update'] .disabled { .modal-content { border-radius: 0; - overflow:auto; + overflow: auto; } } + //end css loader diff --git a/app/assets/stylesheets/clients/index.scss b/app/assets/stylesheets/clients/index.scss index 71a8f0dcb3..167fba6df8 100644 --- a/app/assets/stylesheets/clients/index.scss +++ b/app/assets/stylesheets/clients/index.scss @@ -193,7 +193,8 @@ body[id='clients-index'] { display: none; } - .client-column-picker, .custom-form, .program-stream, .selected-custom-form, .program-association, #wizard-referral-data, #wizard-program-stream, #wizard-custom-form { + .client-column-picker, .custom-form, .program-stream, .selected-custom-form, .program-association, + #wizard-referral-data, #wizard-program-stream, #wizard-custom-form, .assessment-form { display: none; } diff --git a/app/assets/stylesheets/common_index.scss b/app/assets/stylesheets/common_index.scss index 4d2ae6f510..63f448e84a 100644 --- a/app/assets/stylesheets/common_index.scss +++ b/app/assets/stylesheets/common_index.scss @@ -3,17 +3,20 @@ border-radius: 1px !important; box-shadow: none !important; } + .datepicker table tr td.active.active, .datepicker table tr td.active:hover:hover { background-color: #1ab394; background-image: none; color: white; } + .select2-results .select2-highlighted, .select2-highlighted:hover { background-color: #1ab394; color: white; } + .select2-container .select2-choices .select2-search-field input, .select2-container .select2-choice, .select2-container .select2-choices { @@ -21,63 +24,78 @@ box-shadow: none !important; border-radius: 1px !important; } + .select2-drop-active { border: 1px solid #1ab394 !important; border-top: none !important; box-shadow: none !important; } + .datepicker.datepicker-dropdown.dropdown-menu { z-index: 330000 !important; } + .ibox-title span { font-size: 12px; } + .select2-container-active .select2-choice, .select2-container-multi.select2-container-active .select2-choices { box-shadow: none !important; border: 1px solid #1ab394 !important; border-radius: 1px !important; } -#toast-container > div { + +#toast-container>div { width: 400px !important; } + .btn-back-default { color: #756e6c !important; background: white; border: 1px solid #e7eaec; } + .line-border { border-top: 1px solid #86898c; } + .log-min { background: white; border: 3px solid white; padding: 1px; border-radius: 50% 50%; } + .img-circle { background: white; border: 10px solid white; width: 100px; } + .btn-back-default:hover { color: #756e6c; } + .min-margin-layout { margin-top: 16px; } + .boolean.optional { padding: 0; } -.ibox-title > h5, -.panel-heading > h5 { + +.ibox-title>h5, +.panel-heading>h5 { font-size: 16px; font-weight: 600; color: #6b6a6c; } + .mini-margin { margin-top: 16px; } + .bg { background: white; } @@ -106,6 +124,7 @@ display: block; height: 60px; margin-top: -7px; + img { margin: 0; width: 30px; @@ -117,6 +136,7 @@ .notify-margin { margin-left: 20px; } + .chevron-progess-note { margin-right: -16px; } @@ -140,6 +160,7 @@ .staging-identifier { background: #c52f24; + .message-staging { color: #fff; margin: 0; @@ -152,12 +173,15 @@ .record-count { margin: 15px 0; } + .custom_column_manage { width: 20%; } + .custom_column_name { width: 40%; } + .custom_column_description { width: 40%; } @@ -199,11 +223,13 @@ ul.dropdown-menu.dropdown-alerts { .notification-text-color { color: #1ab394; } + .fcf_ngo { margin-top: 40px; font-size: 20px; color: grey; } + .align-link { margin-top: -18px; margin-bottom: -18px; @@ -221,6 +247,7 @@ ul.dropdown-menu.dropdown-alerts { .dropdown-menu li a { padding: 0 5px; min-height: 0; + img { margin-right: 3px; } @@ -252,6 +279,7 @@ span.input-group-addon { } @media print { + body, p, label, @@ -296,3 +324,22 @@ span.input-group-addon { .nowrap { white-space: nowrap; } + +fieldset.fieldset-border { + border: solid 1px #DDD !important; + padding: 0 10px 10px 10px; + border-bottom: none; + margin-bottom: 25px; + border-radius: 4px; + + legend.legend-border { + width: auto !important; + border: none; + } + + span { + label.collection_radio_buttons { + margin-left: 5px; + } + } +} diff --git a/app/assets/stylesheets/datatable/table.scss b/app/assets/stylesheets/datatable/table.scss new file mode 100644 index 0000000000..9e4b515741 --- /dev/null +++ b/app/assets/stylesheets/datatable/table.scss @@ -0,0 +1,12 @@ +table { + &.table-bordered { + border-right-width: 0; + &.dataTable { + th, td { + &:last-child { + border-right-width: 1px; + } + } + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/screening_assessments/form.scss b/app/assets/stylesheets/screening_assessments/form.scss new file mode 100644 index 0000000000..7b460d588c --- /dev/null +++ b/app/assets/stylesheets/screening_assessments/form.scss @@ -0,0 +1,8 @@ +body[id='screening_assessments-new'], +body[id='screening_assessments-create'], +body[id='screening_assessments-edit'], +body[id='screening_assessments-update'] { + .collection_radio_buttons { + margin-left: 5px; + } +} diff --git a/app/classes/ability.rb b/app/classes/ability.rb index e7fbfc3b5f..e923d91f7d 100644 --- a/app/classes/ability.rb +++ b/app/classes/ability.rb @@ -54,6 +54,7 @@ def initialize(user) can :manage, Enrollment can :manage, Community can :manage, EnrollmentTracking + can :manage, ScreeningAssessment, clients: { case_worker_clients: { user_id: user.id } } family_ids = user.families.ids family_ids << CaseWorkerFamily.where(user_id: user.id).pluck(:family_id) @@ -94,6 +95,7 @@ def initialize(user) can :manage, Enrollment can :manage, Community can :manage, EnrollmentTracking + can :manage, ScreeningAssessment, clients: { case_worker_clients: { user_id: user.id } } family_ids = user.families.ids family_ids += User.joins(:clients).where(id: subordinate_users).where.not(clients: { current_family_id: nil }).select('clients.current_family_id AS client_current_family_id').map(&:client_current_family_id) @@ -125,6 +127,7 @@ def initialize(user) cannot [:edit, :update], ReferralSource cannot :destroy, Client can :manage, Family + can :manage, ScreeningAssessment, clients: { case_worker_clients: { user_id: user.id } } end cannot :read, Community if Setting.cache_first.hide_community? diff --git a/app/classes/advanced_searches/client_association_filter.rb b/app/classes/advanced_searches/client_association_filter.rb index 933c040a26..1b9c94da83 100644 --- a/app/classes/advanced_searches/client_association_filter.rb +++ b/app/classes/advanced_searches/client_association_filter.rb @@ -118,6 +118,20 @@ def get_sql values = care_plan_counter when 'care_plan_completed_date' values = date_query(Client, @clients, :care_plans, 'care_plans.created_at') + when 'number_client_referred_gatekeeping' + values = number_client_referred_gatekeeping_query + when 'number_client_billable' + values = number_client_billable_query + when 'active_client_program' + values = active_client_program_query + when 'assessment_condition_last_two' + values = assessment_condition_last_two_query + when 'assessment_condition_first_last' + values = assessment_condition_first_last_query + when 'client_rejected' + values = get_rejected_clients + when 'incomplete_care_plan' + values = incomplete_care_plan_query end { id: sql_string, values: values } end @@ -1114,5 +1128,274 @@ def referred_in_out_query(referral_scope) end clients.ids end + + def number_client_referred_gatekeeping_query + clients = @clients.where(referral_source_category_id: ReferralSource.gatekeeping_mechanism.ids).distinct + + case @operator + when 'equal' + client_ids = clients.where('date(initial_referral_date) = ?', @value.to_date ).distinct.ids + when 'not_equal' + client_ids = clients.where('date(initial_referral_date) != ?', @value.to_date ).distinct.ids + when 'between' + client_ids = clients.where("date(initial_referral_date) BETWEEN ? AND ? ", @value[0].to_date, @value[1].to_date).distinct.ids + when 'less' + client_ids = clients.where('date(initial_referral_date) < ?', @value.to_date ).distinct.ids + when 'less_or_equal' + client_ids = clients.where('date(initial_referral_date) <= ?', @value.to_date ).distinct.ids + when 'greater' + client_ids = clients.where('date(initial_referral_date) > ?', @value.to_date ).distinct.ids + when 'greater_or_equal' + client_ids = clients.where('date(initial_referral_date) >= ?', @value.to_date ).distinct.ids + when 'is_empty' + client_ids = clients.where('initial_referral_date IS NULL').distinct.ids + when 'is_not_empty' + client_ids = clients.where('initial_referral_date IS NOT NULL').distinct.ids + end + clients = client_ids.present? ? client_ids : [] + end + + def number_client_billable_query + value = @value.kind_of?(Array) ? @value[0] : @value.to_date + clients = @clients.joins(:enter_ngos).includes(:exit_ngos).where('(exit_ngos.exit_date IS NULL OR date(exit_ngos.exit_date) >= ?)', value).distinct + + case @operator + when 'equal' + client_ids = clients.where('date(enter_ngos.accepted_date) = ?', @value.to_date).distinct.ids + when 'not_equal' + client_ids = clients.where('date(enter_ngos.accepted_date) != ?', @value.to_date).distinct.ids + when 'between' + client_ids = clients.where("date(enter_ngos.accepted_date) <= ?", @value[1]).distinct.ids + when 'less' + client_ids = clients.where('date(enter_ngos.accepted_date) < ?', @value.to_date).distinct.ids + when 'less_or_equal' + client_ids = clients.where('date(enter_ngos.accepted_date) <= ?', @value.to_date).distinct.ids + when 'greater' + client_ids = clients.where('date(enter_ngos.accepted_date) > ?', @value.to_date).distinct.ids + when 'greater_or_equal' + client_ids = clients.where('date(enter_ngos.accepted_date) >= ?', @value.to_date).distinct.ids + when 'is_empty' + client_ids = clients.where('enter_ngos.accepted_date IS NULL').distinct.ids + when 'is_not_empty' + client_ids = clients.where('enter_ngos.accepted_date IS NOT NULL').distinct.ids + end + clients = client_ids.present? ? client_ids : [] + end + + def get_rejected_clients + client_ids = [] + clients = @clients.joins(:exit_ngos).where(:exit_ngos => {:exit_circumstance => 'Rejected Referral'}).distinct + + case @operator + when 'equal' + client_ids = clients.where('date(exit_ngos.exit_date) = ?', @value.to_date ).distinct.ids + when 'not_equal' + client_ids = clients.where('date(exit_ngos.exit_date) != ?', @value.to_date ).distinct.ids + when 'between' + client_ids = clients.where("date(exit_ngos.exit_date) BETWEEN ? AND ?", @value[0], @value[1]).distinct.ids + when 'less' + client_ids = clients.where('date(exit_ngos.exit_date) < ?', @value.to_date ).distinct.ids + when 'less_or_equal' + client_ids = clients.where('date(exit_ngos.exit_date) <= ?', @value.to_date ).distinct.ids + when 'greater' + client_ids = clients.where('date(exit_ngos.exit_date) > ?', @value.to_date ).distinct.ids + when 'greater_or_equal' + client_ids = clients.where('date(exit_ngos.exit_date) >= ?', @value.to_date ).distinct.ids + when 'is_empty' + client_ids = clients.where('exit_ngos.exit_date IS NULL').distinct.ids + when 'is_not_empty' + client_ids = clients.where('exit_ngos.exit_date IS NOT NULL').distinct.ids + end + clients = client_ids + end + + def active_client_program_between(start_date, end_date, clientIds) + enrollments = ClientEnrollment.where(:client_id => clientIds) + client_ids = [] + enrollments.each do |enrollment| + enrollment_date = enrollment.enrollment_date + + if enrollment.leave_program.present? + exit_date = enrollment.leave_program.exit_date + if enrollment_date < start_date || enrollment_date.between?(start_date, end_date) + client_ids << enrollment.client_id if exit_date.between?(start_date, end_date) || exit_date > end_date + end + else + client_ids << enrollment.client_id if enrollment_date.between?(start_date, end_date) || enrollment_date < start_date + end + end + client_ids + end + + def active_client_program_query + clientIds = [] + JSON.parse($param_rules[:program_selected]).each do |program| + tmpClientIds = @clients.joins(:client_enrollments).where(:client_enrollments => {:status => 'Active', :program_stream_id => program}).ids + if clientIds.empty? + clientIds = tmpClientIds + else + clientIds = clientIds & tmpClientIds + end + end + + condition = '' + start_date = @value.kind_of?(Array) ? @value[0].to_date : @value.to_date + + case @operator + when 'equal' + condition = "date(client_enrollments.enrollment_date) = '#{start_date}'" + when 'not_equal' + condition = "date(client_enrollments.enrollment_date) != '#{start_date}'" + when 'between' + condition = "date(client_enrollments.enrollment_date) <= '#{@value[1].to_date}'" + when 'less' + condition = "date(client_enrollments.enrollment_date) < '#{start_date}'" + when 'less_or_equal' + condition = "date(client_enrollments.enrollment_date) <= '#{start_date}'" + when 'greater' + condition = "date(client_enrollments.enrollment_date) > '#{start_date}'" + when 'greater_or_equal' + condition = "date(client_enrollments.enrollment_date) >= '#{start_date}'" + when 'is_empty' + condition = "client_enrollments.enrollment_date IS NULL" + when 'is_not_empty' + condition = "client_enrollments.enrollment_date IS NOT NULL" + end + + enrollments = ClientEnrollment.where(:client_id => clientIds).where(condition) + client_ids = [] + enrollments.each do |enrollment| + if enrollment.leave_program.present? && start_date != nil + exit_date = enrollment.leave_program.exit_date + client_ids << enrollment.client_id if exit_date >= start_date + else + client_ids << enrollment.client_id + end + end + client_ids + + clients = client_ids.present? ? client_ids : [] + end + + def assessment_condition_last_two_query + case @value.downcase + when 'better' + client_ids = client_assessment_compare_next_last(:>, $param_rules[:assessment_selected]) + when 'same' + client_ids = client_assessment_compare_next_last(:==, $param_rules[:assessment_selected]) + when 'worse' + client_ids = client_assessment_compare_next_last(:<, $param_rules[:assessment_selected]) + end + clients = client_ids.present? ? client_ids : [] + end + + def assessment_condition_first_last_query + case @value.downcase + when 'better' + client_ids = client_assessment_compare_first_last(:>, $param_rules[:assessment_selected]) + when 'same' + client_ids = client_assessment_compare_first_last(:==, $param_rules[:assessment_selected]) + when 'worse' + client_ids = client_assessment_compare_first_last(:<, $param_rules[:assessment_selected]) + end + clients = client_ids.present? ? client_ids : [] + end + + def client_assessment_compare_first_last(compare, selectedAssessment) + client_ids = [] + clients = @clients.joins(:assessments).where(assessments: { completed: true }) + conditionString = "" + if selectedAssessment.present? + assessments = JSON.parse(selectedAssessment) + assessmentId = assessments.first + + if assessmentId == 0 + clients = clients.where("assessments.default = true").distinct + domains = Domain.csi_domains + clients.each do |client| + last_assessment = client.assessments.defaults.most_recents.first + first_assessment = client.assessments.defaults.most_recents.last + if (client.assessments.defaults.length > 1) + client_ids << client.id if assessment_total_score(last_assessment, domains).public_send(compare, assessment_total_score(first_assessment, domains)) + end + end + else + assessments = Assessment.completed.joins(:domains).where(client_id: clients.ids).where("domains.custom_assessment_setting_id IN (#{assessmentId})").distinct + + assessments.group_by { |assessment| assessment.client_id }.each do |client_id, _assessments| + next if _assessments.size < 2 + + first_assessment = _assessments.sort_by(&:id).first + last_assessment = _assessments.sort_by(&:id).last + + first_assessment_domain_scores = first_assessment.assessment_domains.pluck(:score).sum.to_f + last_assessment_domain_scores = last_assessment.assessment_domains.pluck(:score).sum.to_f + + first_average_score = (first_assessment_domain_scores / first_assessment.assessment_domains.size).round + last_average_score = (last_assessment_domain_scores / last_assessment.assessment_domains.size).round + client_ids << client_id if last_average_score.public_send(compare, first_average_score) + end + end + end + client_ids + end + + def client_assessment_compare_next_last(compare, selectedAssessment) + client_ids = [] + clients = @clients.joins(:assessments).where(assessments: { completed: true }) + conditionString = "" + if selectedAssessment.present? + assessments = JSON.parse(selectedAssessment) + assessmentId = assessments.first + + if assessmentId == 0 + domains = Domain.csi_domains + clients = clients.where("assessments.default = true").distinct + clients.each do |client| + last_assessment = client.assessments.defaults.most_recents.first + next_assessment = client.assessments.defaults.length > 1 ? client.assessments.defaults.most_recents.fetch(1) : last_assessment + if (client.assessments.defaults.length > 1) + client_ids << client.id if assessment_total_score(last_assessment, domains).public_send(compare, assessment_total_score(next_assessment, domains)) + end + end + else + assessments = Assessment.completed.joins(:domains).where(client_id: clients.ids).where("domains.custom_assessment_setting_id IN (#{assessmentId})").distinct + + assessments.group_by { |assessment| assessment.client_id }.each do |client_id, _assessments| + next if _assessments.size < 2 + + before_last_assessment = _assessments.sort_by(&:id).fetch(_assessments.size - 2) + last_assessment = _assessments.sort_by(&:id).last + + before_last_assessment_domain_scores = before_last_assessment.assessment_domains.pluck(:score).sum.to_f + last_assessment_domain_scores = last_assessment.assessment_domains.pluck(:score).sum.to_f + + before_last_assessment_average_score = (before_last_assessment_domain_scores / before_last_assessment.assessment_domains.size).round + last_average_score = (last_assessment_domain_scores / last_assessment.assessment_domains.size).round + client_ids << client_id if last_average_score.public_send(compare, before_last_assessment_average_score) + end + end + end + client_ids + end + + def assessment_total_score(assessment, domains) + assessment_domain_hash = AssessmentDomain.where(assessment_id: assessment.id).pluck(:domain_id, :score).to_h if assessment.assessment_domains.present? + domain_scores = domains.ids.map { |domain_id| assessment_domain_hash.present? ? ["domain_#{domain_id}", assessment_domain_hash[domain_id]] : ["domain_#{domain_id}", ''] } + total = 0 + if assessment_domain_hash.present? + assessment_domain_hash.each do |index, value| + total += value.nil? ? 0 : value + end + end + (total.fdiv(domain_scores.length())).round() + end + + def incomplete_care_plan_query + clients = @clients.joins(:care_plans).where(care_plans: { completed: false }).distinct + + client_ids = clients.ids + clients = client_ids.present? ? client_ids : [] + end end end diff --git a/app/classes/advanced_searches/client_base_sql_builder.rb b/app/classes/advanced_searches/client_base_sql_builder.rb index 64ae60d434..70827a92b1 100644 --- a/app/classes/advanced_searches/client_base_sql_builder.rb +++ b/app/classes/advanced_searches/client_base_sql_builder.rb @@ -12,7 +12,10 @@ class ClientBaseSqlBuilder 'referee_name', 'referee_phone', 'referee_email', 'carer_name', 'carer_phone', 'carer_email', 'client_phone', 'client_email_address', 'phone_owner', 'referee_relationship', 'active_clients', 'care_plan_counter', 'care_plan_completed_date', 'completed_date', 'custom_completed_date', 'carer_relationship_to_client', - 'referred_in', 'referred_out', 'family_type', 'ratanak_achievement_program_staff_client_ids', 'mo_savy_officials' + 'ratanak_achievement_program_staff_client_ids', 'mo_savy_officials', + 'referred_in', 'referred_out', 'family_type', 'active_client_program', + 'number_client_referred_gatekeeping', 'number_client_billable', 'assessment_condition_last_two', + 'assessment_condition_first_last', 'client_rejected', 'incomplete_care_plan' ] BLANK_FIELDS = ['created_at', 'date_of_birth', 'initial_referral_date', 'follow_up_date', 'has_been_in_orphanage', 'has_been_in_government_care', 'province_id', 'referral_source_id', 'birth_province_id', 'received_by_id', 'followed_up_by_id', 'district_id', 'subdistrict_id', 'township_id', 'state_id', 'commune_id', 'village_id', 'referral_source_category_id', 'arrival_at'] diff --git a/app/classes/advanced_searches/client_fields.rb b/app/classes/advanced_searches/client_fields.rb index 0d1ffbfa65..b90548969c 100644 --- a/app/classes/advanced_searches/client_fields.rb +++ b/app/classes/advanced_searches/client_fields.rb @@ -9,25 +9,41 @@ class ClientFields def initialize(options = {}) @user = options[:user] @pundit_user = options[:pundit_user] + @program_stream_ids = options[:program_stream_ids] address_translation end def render + common_group = format_header('common_searches') group = format_header('basic_fields') + care_plan_group = format_header('care_plan') referee_group = format_header('referee') carer_group = format_header('carer') legal_docs = format_header('legal_documents') + case_history_group = format_header('case_history') + family_group = format_header('family') + case_note_group = format_header('case_note') + other_group = format_header('other') number_fields = number_type_list.map { |item| AdvancedSearches::FilterTypes.number_options(item, format_header(item), group) } + number_fields += case_history_number_type_list.map { |item| AdvancedSearches::FilterTypes.number_options(item, format_header(item), case_history_group) } text_fields = text_type_list.map { |item| AdvancedSearches::FilterTypes.text_options(item, format_header(item), group) } - text_fields << referee_text_fields.map { |item| AdvancedSearches::FilterTypes.text_options(item, format_header(item), referee_group) } - text_fields << carer_text_fields.map { |item| AdvancedSearches::FilterTypes.text_options(item, format_header(item), carer_group) } - date_picker_fields = date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, format_header(item), group) } - date_picker_fields += [['no_case_note_date', I18n.t('advanced_search.fields.no_case_note_date')]].map{ |item| AdvancedSearches::CsiFields.date_between_only_options(item[0], item[1], group) } + date_picker_fields = common_search_date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, format_header(item), common_group) } + date_picker_fields += date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, format_header(item), group) } + date_picker_fields += case_history_date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, format_header(item), case_history_group) } + date_picker_fields += case_note_date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, format_header(item), case_note_group) } + date_picker_fields += [['no_case_note_date', I18n.t('advanced_search.fields.no_case_note_date')]].map{ |item| AdvancedSearches::CsiFields.date_between_only_options(item[0], item[1], case_note_group) } date_picker_fields += mapping_care_plan_date_lable_translation + date_picker_fields += other_date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, format_header(item), other_group) } drop_list_fields = drop_down_type_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, group) } + drop_list_fields += care_plan_dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, care_plan_group) } + drop_list_fields += referee_dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, referee_group) } drop_list_fields += carer_dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, carer_group) } drop_list_fields += legal_docs_dropdown.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, legal_docs) } + drop_list_fields += family_dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, family_group) } + drop_list_fields += case_history_dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, case_history_group) } + drop_list_fields += case_note_dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, case_note_group) } + drop_list_fields += other_dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, other_group) } csi_options = AdvancedSearches::CsiFields.render school_grade_options = AdvancedSearches::SchoolGradeFields.render default_domain_scores_options = enable_default_assessment? ? AdvancedSearches::DomainScoreFields.render : [] @@ -43,73 +59,67 @@ def render private def number_type_list - ['family_id', 'age', 'time_in_cps', 'time_in_ngo', 'referred_in', 'referred_out'] + ['family_id', 'age'] + end + + def case_history_number_type_list + ['referred_in', 'referred_out', 'time_in_ngo', 'time_in_cps'] end def text_type_list [ - 'given_name', 'family_name', 'flight_nb', - 'local_given_name', 'local_family_name', 'family', 'slug', 'school_name', - 'other_info_of_exit', 'exit_note', 'main_school_contact', 'what3words', 'kid_id', 'code', - 'client_phone', 'client_email_address', *setting_country_fields[:text_fields] + 'given_name', 'flight_nb','local_given_name', 'slug', 'what3words', 'kid_id', 'code', + 'client_email_address', *setting_country_fields[:text_fields] ].compact end - def referee_text_fields - ['referee_name', 'referee_phone', 'referee_email'] - end - - def carer_text_fields - ['carer_name', 'carer_phone', 'carer_email'] + def referee_dropdown_list + [ + ['referral_source_category_id', referral_source_category_options], + ['referral_source_id', referral_source_options], + ['referee_relationship', get_sql_referee_relationship] + ] end def current_user @pundit_user end + def common_search_date_type_list + ['number_client_referred_gatekeeping', 'number_client_billable', 'client_rejected', 'active_clients'] + end + def date_type_list [ - 'date_of_birth', 'initial_referral_date', 'follow_up_date', 'exit_date', 'accepted_date', - 'case_note_date', 'created_at', 'date_of_referral', 'active_clients', 'arrival_at' + 'date_of_birth', 'date_of_referral' ].compact end + def case_history_date_type_list + ['initial_referral_date', 'follow_up_date', 'accepted_date', 'exit_date'] + end + + def case_note_date_type_list + ['case_note_date'] + end + + def other_date_type_list + ['created_at'] + end + def drop_down_type_list + yes_option = { true: 'Yes' } yes_no_options = { true: 'Yes', false: 'No' } fields = [ ['location_of_concern', Client.cache_location_of_concern], - ['created_by', user_select_options ], ['gender', gender_list], ['status', client_status], - ['agency_name', agencies_options], - ['received_by_id', received_by_options], - ['referral_source_id', referral_source_options], - ['followed_up_by_id', followed_up_by_options], - ['has_been_in_government_care', yes_no_options], - ['has_overdue_assessment', yes_no_options], - ['has_overdue_forms', yes_no_options], - ['has_overdue_task', yes_no_options], - ['no_case_note', yes_no_options], - ['has_been_in_orphanage', yes_no_options], - ['user_id', user_select_options], ['ratanak_achievement_program_staff_client_ids', user_select_options], ['mo_savy_officials', mo_savy_officials_options], - ['donor_name', donor_options], - ['active_program_stream', active_program_options], - ['enrolled_program_stream', enrolled_program_options], - ['case_note_type', case_note_type_options], - ['exit_reasons', exit_reasons_options], - ['exit_circumstance', {'Exited Client': 'Exited Client', 'Rejected Referral': 'Rejected Referral'}], *rated_id_poor, *setting_country_fields[:drop_down_fields], - ['referred_to', referral_to_options], - ['referred_from', referral_from_options], - ['referral_source_category_id', referral_source_category_options], - ['type_of_service', get_type_of_services], - ['referee_relationship', get_sql_referee_relationship], ['address_type', get_sql_address_types], ['phone_owner', get_sql_phone_owner], - ['family_type', family_type_list] ].compact end @@ -118,12 +128,62 @@ def legal_docs_dropdown legal_doc_fields.map{|field| [field, yes_no_options] } end + def care_plan_dropdown_list + yes_option = { true: 'Yes' } + [ + ['incomplete_care_plan', yes_option] + ] + end + def carer_dropdown_list [ ['carer_relationship_to_client', list_carer_client_relations] ] end + def family_dropdown_list + [ + ['family_type', family_type_list] + ] + end + + def case_history_dropdown_list + yes_no_options = { true: 'Yes', false: 'No' } + [ + ['user_id', user_select_options], + ['exit_circumstance', {'Exited Client': 'Exited Client', 'Rejected Referral': 'Rejected Referral'}], + ['followed_up_by_id', followed_up_by_options], + ['referred_from', referral_from_options], + ['referred_to', referral_to_options], + ['exit_reasons', exit_reasons_options], + ['received_by_id', received_by_options], + ['active_program_stream', active_program_options], + ['enrolled_program_stream', enrolled_program_options], + ['donor_name', donor_options], + ['has_been_in_orphanage', yes_no_options], + ['has_been_in_government_care', yes_no_options], + ] + end + + def case_note_dropdown_list + yes_no_options = { true: 'Yes', false: 'No' } + [ + ['case_note_type', case_note_type_options], + ['no_case_note', yes_no_options], + ] + end + + def other_dropdown_list + yes_no_options = { true: 'Yes', false: 'No' } + [ + ['agency_name', agencies_options], + ['created_by', user_select_options ], + ['type_of_service', get_type_of_services], + ['has_overdue_forms', yes_no_options], + ['has_overdue_task', yes_no_options], + ] + end + def field_settings @field_settings = FieldSetting.cache_all end diff --git a/app/classes/advanced_searches/common_fields.rb b/app/classes/advanced_searches/common_fields.rb new file mode 100644 index 0000000000..0814cd3061 --- /dev/null +++ b/app/classes/advanced_searches/common_fields.rb @@ -0,0 +1,36 @@ +module AdvancedSearches + class CommonFields + + include AdvancedSearchHelper + + def initialize(program_ids = nil, assessment_checked = false) + @program_ids = program_ids + @assessment_checked = assessment_checked + + address_translation + end + + def render + common_group = format_header('common_searches') + + date_picker_fields = @program_ids.nil? ? [] : common_search_date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, format_header(item), common_group) } + drop_down_fields = @assessment_checked ? common_search_dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, common_group) } : [] + + results = date_picker_fields + drop_down_fields + + results.sort_by { |f| f[:label].downcase } + end + + def common_search_date_type_list + ['active_client_program'] + end + + def common_search_dropdown_list + better_same_worse_options = { better: 'Better', same: 'The same', worse: 'Worse' } + [ + ['assessment_condition_last_two', better_same_worse_options], + ['assessment_condition_first_last', better_same_worse_options] + ] + end + end +end diff --git a/app/classes/advanced_searches/csi_fields.rb b/app/classes/advanced_searches/csi_fields.rb index f349f7abe6..3c5095a1bb 100644 --- a/app/classes/advanced_searches/csi_fields.rb +++ b/app/classes/advanced_searches/csi_fields.rb @@ -7,9 +7,8 @@ def self.render address_translation csi_group = format_header('custom_csi_group') csi_domain_options = number_type_list.map { |item| number_filter_type(item, format_header(item), csi_group) } - assessment_completed = [['assessment_completed', I18n.t('clients.index.assessment_completed', assessment: I18n.t('clients.show.assessment'))]].map{ |item| date_between_only_options(item[0], item[1], csi_group) } date_nearest = ['Date Nearest'].map{ |item| date_nearest(item.downcase.gsub(' ', '_'), item, csi_group) } - (assessment_completed + csi_domain_options + date_nearest).sort_by { |f| f[:label].downcase } + (csi_domain_options + date_nearest).sort_by { |f| f[:label].downcase } end private @@ -43,13 +42,13 @@ def self.date_picker_options(field_name, label, group) } end - def self.date_between_only_options(field_name, label, group) + def self.date_nearest(field_name, label, group) { id: field_name, optgroup: group, label: label, type: 'date', - operators: ['between'], + operators: ['equal'], plugin: 'datepicker', plugin_config: { format: 'yyyy-mm-dd', @@ -60,14 +59,23 @@ def self.date_between_only_options(field_name, label, group) } end + def self.number_filter_type(field_name, label, group) + { + id: field_name, + optgroup: group, + label: label, + type: 'integer', + operators: ['equal'] + } + end - def self.date_nearest(field_name, label, group) + def self.date_between_only_options(field_name, label, group) { id: field_name, optgroup: group, label: label, type: 'date', - operators: ['equal'], + operators: ['between'], plugin: 'datepicker', plugin_config: { format: 'yyyy-mm-dd', @@ -77,15 +85,5 @@ def self.date_nearest(field_name, label, group) } } end - - def self.number_filter_type(field_name, label, group) - { - id: field_name, - optgroup: group, - label: label, - type: 'integer', - operators: ['equal'] - } - end end end diff --git a/app/classes/advanced_searches/custom_domain_score_fields.rb b/app/classes/advanced_searches/custom_domain_score_fields.rb index 3789238f65..f28e01950f 100644 --- a/app/classes/advanced_searches/custom_domain_score_fields.rb +++ b/app/classes/advanced_searches/custom_domain_score_fields.rb @@ -10,7 +10,7 @@ def self.render(domain_type = 'client') assessment_completed_date = ['custom_completed_date'].map{ |item| date_picker_options(item, format_header(item), domain_score_group) } date_of_assessments = ['custom_assessment_created_date'].map{ |item| date_picker_options(item, format_header(item), domain_score_group) } all_custom_domains = ['All Custom Domains'].map { |item| number_filter_type(item.downcase.gsub(' ', '_'), domain_score_format(item), domain_score_group) } - all_custom_domains + custom_assessments + date_of_assessments + assessment_completed_date + csi_domain_options + (custom_assessments + date_of_assessments + assessment_completed_date + csi_domain_options + all_custom_domains).sort_by { |f| f[:label].downcase } end private diff --git a/app/classes/advanced_searches/domain_score_fields.rb b/app/classes/advanced_searches/domain_score_fields.rb index 1e20638b6c..866261c622 100644 --- a/app/classes/advanced_searches/domain_score_fields.rb +++ b/app/classes/advanced_searches/domain_score_fields.rb @@ -9,7 +9,9 @@ def self.render date_of_assessments = [['date_of_assessments', I18n.t('clients.index.date_of_assessment', assessment: I18n.t('clients.show.assessment'))]].map{ |item| date_picker_options(item[0], item[1], domain_score_group) } completed_date_assessments = [['completed_date', I18n.t('advanced_search.fields.assessment_completed_date', assessment: I18n.t('clients.show.assessment'))]].map{ |item| date_picker_options(item[0], item[1], domain_score_group) } all_domains = ['All Domains'].map { |item| number_filter_type(item.downcase.gsub(' ', '_'), domain_score_format(item), domain_score_group) } - all_domains + date_of_assessments + completed_date_assessments + csi_domain_options + drop_list_fields = dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, domain_score_group) } + assessment_completed = [['assessment_completed', I18n.t('clients.index.assessment_completed', assessment: I18n.t('clients.show.assessment'))]].map{ |item| date_between_only_options(item[0], item[1], domain_score_group) } + (csi_domain_options + date_of_assessments + completed_date_assessments + all_domains + drop_list_fields).sort_by { |f| f[:label].downcase } end private @@ -53,5 +55,29 @@ def self.number_filter_type(field_name, label, group) operators: ['equal', 'not_equal', 'less', 'less_or_equal', 'greater', 'greater_or_equal', 'between', 'is_empty', 'is_not_empty', 'average', 'assessment_has_changed', 'assessment_has_not_changed', 'month_has_changed', 'month_has_not_changed'] } end + + def self.dropdown_list + yes_no_options = { true: 'Yes', false: 'No' } + [ + ['has_overdue_assessment', yes_no_options], + ].compact + end + + def self.date_between_only_options(field_name, label, group) + { + id: field_name, + optgroup: group, + label: label, + type: 'date', + operators: ['between'], + plugin: 'datepicker', + plugin_config: { + format: 'yyyy-mm-dd', + todayBtn: 'linked', + todayHighlight: true, + autoclose: true + } + } + end end end diff --git a/app/classes/advanced_searches/filter_types.rb b/app/classes/advanced_searches/filter_types.rb index ba77d89c02..d399b971bb 100644 --- a/app/classes/advanced_searches/filter_types.rb +++ b/app/classes/advanced_searches/filter_types.rb @@ -1,6 +1,6 @@ module AdvancedSearches class FilterTypes - OVERDUE_FIELDS = %w(has_overdue_assessment has_overdue_forms has_overdue_task no_case_note) + OVERDUE_FIELDS = %w(has_overdue_assessment has_overdue_forms has_overdue_task no_case_note assessment_condition_last_two assessment_condition_first_last incomplete_care_plan) def self.text_options(field_name, label, group) { id: field_name, diff --git a/app/classes/advanced_searches/quantitative_case_fields.rb b/app/classes/advanced_searches/quantitative_case_fields.rb index 396512f348..8954860d92 100644 --- a/app/classes/advanced_searches/quantitative_case_fields.rb +++ b/app/classes/advanced_searches/quantitative_case_fields.rb @@ -18,7 +18,6 @@ def render quantitative_type_ids = @user.quantitative_type_permissions.readable.pluck(:quantitative_type_id) quantitative_types = QuantitativeType.cach_by_quantitative_type_ids(quantitative_type_ids) end - quantitative_cases = quantitative_types.map do |qt| if qt.select_option? AdvancedSearches::FilterTypes.drop_list_options( diff --git a/app/classes/risk_assessment_reducer.rb b/app/classes/risk_assessment_reducer.rb new file mode 100644 index 0000000000..1f46e1cf20 --- /dev/null +++ b/app/classes/risk_assessment_reducer.rb @@ -0,0 +1,19 @@ +class RiskAssessmentReducer + attr_reader :type, :risk_assessment, :risk_assessment_params + def initialize(client, risk_assessment_params, type = 'create') + @risk_assessment = client.risk_assessment.present? ? client.risk_assessment : client.build_risk_assessment(risk_assessment_params) + @risk_assessment_params = risk_assessment_params + @type = type if risk_assessment_params[:assessment_date].present? + end + + def store + case type + when 'create' + risk_assessment.save + when 'update' + risk_assessment.persisted? ? risk_assessment.update_attributes(risk_assessment_params) : risk_assessment.save + else + false + end + end +end diff --git a/app/classes/tracking_datatable.rb b/app/classes/tracking_datatable.rb index 8076f6dc43..b62e0c8d7b 100644 --- a/app/classes/tracking_datatable.rb +++ b/app/classes/tracking_datatable.rb @@ -24,7 +24,7 @@ def sort_column def fetch_trackings program_stream_ids = ClientEnrollment.active.pluck(:program_stream_id).uniq - Tracking.unscoped.includes(:client_enrollments, :program_stream).where(program_streams: { id: program_stream_ids }).order("lower(#{sort_column}) #{sort_direction}").page(page).per(per_page) + Tracking.unscoped.includes(:client_enrollments, :program_stream).where(program_streams: { id: program_stream_ids }).order("lower(#{sort_column}), trackings.id #{sort_direction}").page(page).per(per_page) end def columns diff --git a/app/controllers/api/application_controller.rb b/app/controllers/api/application_controller.rb index 4ac4f3f1fc..b885b13b16 100644 --- a/app/controllers/api/application_controller.rb +++ b/app/controllers/api/application_controller.rb @@ -1,7 +1,10 @@ module Api class ApplicationController < ActionController::Base + include LocaleConcern + before_action :authenticate_user! before_action :set_paper_trail_whodunnit + before_action :set_locale private diff --git a/app/controllers/api/client_advanced_searches_controller.rb b/app/controllers/api/client_advanced_searches_controller.rb index a389afe391..3a46fca6c1 100644 --- a/app/controllers/api/client_advanced_searches_controller.rb +++ b/app/controllers/api/client_advanced_searches_controller.rb @@ -29,5 +29,12 @@ def get_exit_program_field advanced_filter_exit_program_field = AdvancedSearches::ExitProgramFields.new(program_stream_ids).render render json: advanced_filter_exit_program_field end + + def get_program_stream_search_field + program_stream_ids = params[:ids] + assessment_checked = params[:assesment_checked] + advanced_filter_common_field = AdvancedSearches::CommonFields.new(program_stream_ids, assessment_checked).render + render json: advanced_filter_common_field + end end end diff --git a/app/controllers/api/clients_controller.rb b/app/controllers/api/clients_controller.rb index 69f9a5c306..abf9827f3c 100644 --- a/app/controllers/api/clients_controller.rb +++ b/app/controllers/api/clients_controller.rb @@ -63,6 +63,11 @@ def create end end + if risk_assessment_params + risk_assessment = RiskAssessmentReducer.new(client, risk_assessment_params, 'create') + risk_assessment.store + end + render json: { slug: client.slug, id: client.id }, status: :ok else render json: client.errors, status: :unprocessable_entity @@ -71,7 +76,6 @@ def create def update client = Client.find(params[:client][:id] || params[:id]) - if params[:client][:id] referee = Referee.find_or_create_by(id: client.referee_id) referee.update_attributes(referee_params) @@ -93,6 +97,11 @@ def update end end + if risk_assessment_params + risk_assessment = RiskAssessmentReducer.new(client, risk_assessment_params, 'update') + risk_assessment.store + end + if params[:client][:assessment_id] assessment = Assessment.find(params[:client][:assessment_id]) else @@ -147,11 +156,11 @@ def client_params params[:client][:mo_savy_officials_attributes] = {} params[:mosavy_officials].each_with_index do |item, index| - params[:client][:mo_savy_officials_attributes] [index.to_s] = item + params[:client][:mo_savy_officials_attributes][index.to_s] = item end end - client_params = params.require(:client).permit( + client_param = params.require(:client).permit( :slug, :archived_slug, :code, :name_of_referee, :main_school_contact, :rated_for_id_poor, :what3words, :status, :country_origin, :kid_id, :assessment_id, :given_name, :family_name, :local_given_name, :local_family_name, :gender, :date_of_birth, :birth_province_id, :initial_referral_date, :referral_source_id, :telephone_number, @@ -246,25 +255,18 @@ def client_params field_settings.each do |field_setting| next if field_setting.group != 'client' || field_setting.required? || field_setting.visible? - client_params.except!(field_setting.name.to_sym) unless field_setting.name == 'gender' + client_param.except!(field_setting.name.to_sym) unless field_setting.name == 'gender' end if params[:family_member] - client_params[:family_member_attributes] = params[:family_member].permit([:id, :family_id]) + client_param[:family_member_attributes] = params[:family_member].permit([:id, :family_id]) - if client_params[:family_member_attributes].present? - client_params[:family_member_attributes][:_destroy] = 1 if client_params.dig(:family_member_attributes, :family_id).blank? + if client_param[:family_member_attributes].present? + client_param[:family_member_attributes][:_destroy] = 1 if client_param.dig(:family_member_attributes, :family_id).blank? end end - Client::LEGAL_DOC_FIELDS.each do |attachment_field| - doc_field = attachment_field.gsub('_files', '') - remove_field = "remove_#{attachment_field}" - - # client_params[remove_field.to_sym] = true if client_params[doc_field.to_sym].in?([false, 'false']) - end - - client_params + client_param end def referee_params @@ -281,6 +283,17 @@ def carer_params ) end + def risk_assessment_params + return if params.dig(:risk_assessment).nil? + params.require(:risk_assessment).permit( + :assessment_date, :other_protection_concern_specification, :client_perspective, :has_known_chronic_disease, + :has_disability, :has_hiv_or_aid, :known_chronic_disease_specification, :disability_specification, :hiv_or_aid_specification, + :relevant_referral_information, :level_of_risk, :history_of_disability_id, :history_of_harm_id, :history_of_high_risk_behaviour_id, + :history_of_family_separation_id, protection_concern: [], + tasks_attributes: [:id, :name, :expected_date, :client_id, :_destroy] + ) + end + def find_client_in_organization results = [] similar_fields = Client.find_shared_client(params) @@ -299,11 +312,16 @@ def data assessment_data.each do |assessment| assessment_domain_hash = AssessmentDomain.where(assessment_id: assessment.id).pluck(:domain_id, :score).to_h if assessment.assessment_domains.present? domain_scores = domains.ids.map { |domain_id| assessment_domain_hash.present? ? ["domain_#{domain_id}", assessment_domain_hash[domain_id]] : ["domain_#{domain_id}", ''] } + total = 0 + assessment_domain_hash.each do |index, value| + total += value || 0 + end client_hash = { slug: assessment.client.slug, name: assessment.client.en_and_local_name, - 'assessment-number': assessment.client.assessments.count, - date: assessment.created_at.strftime('%d %B %Y') + 'assessment-number': assessment.client.assessments.where(default: params[:default]).count, + date: assessment.created_at.strftime('%d %B %Y'), + 'average-score': total == 0 ? nil : (total.fdiv(domain_scores.length())).round() } client_hash.merge!(domain_scores.to_h) client_data << client_hash @@ -320,6 +338,9 @@ def fetch_assessments assessments = Assessment.joins(:client).where(default: params[:default], client_id: params[:client_ids].split('/')) assessments = assessments.includes(:assessment_domains).order("#{sort_column} #{sort_direction}").references(:assessment_domains, :client) + basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules + @basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules || "{}").with_indifferent_access + assessment_data = params[:length] != '-1' ? assessments.page(page).per(per_page) : assessments end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index dfa6a03b6d..3fa2e9fb45 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,5 +1,7 @@ class ApplicationController < ActionController::Base include Pundit + include LocaleConcern + protect_from_forgery with: :null_session, except: :index, if: proc { |c| c.request.format == 'application/json' } before_action :store_user_location!, if: :storable_location? before_action :configure_permitted_parameters, if: :devise_controller? @@ -87,19 +89,6 @@ def find_association @province = Province.cached_order_name end - def set_locale - local = I18n.locale - local = current_user.preferred_language if user_signed_in? - local = params[:locale] if params[:locale] && I18n.available_locales.include?(params[:locale].to_sym) - - if detect_browser.present? - flash.clear - flash[:alert] = detect_browser - end - - I18n.locale = local - end - def override_translation I18n.backend.reload! if request.get? && request.format.html? end @@ -121,13 +110,6 @@ def after_sign_in_path_for(_resource_or_scope) stored_location_string && stored_location_string.gsub(/locale\=(en|km|my)/, "locale=#{locale}") || dashboards_path(locale: current_user&.preferred_language || 'en') || super end - def detect_browser - lang = params[:locale] || locale.to_s - if browser.firefox? && browser.platform.mac? && lang == 'km' - "Khmer fonts for Firefox do not render correctly. Please use Google Chrome browser instead if you intend to use OSCaR in Khmer language." - end - end - def storable_location? request.get? && is_navigational_format? && !devise_controller? && !request.xhr? end diff --git a/app/controllers/assessments_controller.rb b/app/controllers/assessments_controller.rb index b4356c60da..716951a53f 100644 --- a/app/controllers/assessments_controller.rb +++ b/app/controllers/assessments_controller.rb @@ -134,8 +134,8 @@ def authorize_assessment end def assessment_params - default_params = params.require(:assessment).permit(:default, :case_conference_id, :custom_assessment_setting_id, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last]) - default_params = params.require(:assessment).permit(:default, :case_conference_id, :custom_assessment_setting_id, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last, attachments: []]) if action_name == 'create' + default_params = params.require(:assessment).permit(:default, :case_conference_id, :custom_assessment_setting_id, :level_of_risk, :description, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last]) + default_params = params.require(:assessment).permit(:default, :case_conference_id, :custom_assessment_setting_id, :level_of_risk, :description, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last, attachments: []]) if action_name == 'create' default_params end diff --git a/app/controllers/case_notes_controller.rb b/app/controllers/case_notes_controller.rb index ec13b1efd7..7e832382c9 100644 --- a/app/controllers/case_notes_controller.rb +++ b/app/controllers/case_notes_controller.rb @@ -41,6 +41,7 @@ def create add_more_attachments(params[:case_note][:attachments]) if params.dig(:case_note, :attachments) @case_note.complete_tasks(params[:case_note][:case_note_domain_groups_attributes], current_user.id) if params.dig(:case_note, :case_note_domain_groups_attributes) create_bulk_task(params[:task], @case_note) if params.has_key?(:task) + @case_note.complete_screening_tasks(params) if params[:case_note].has_key?(:tasks_attributes) create_task_task_progress_notes if params[:from_controller] == "dashboards" @@ -78,6 +79,7 @@ def update @case_note.complete_tasks(params[:case_note][:case_note_domain_groups_attributes], current_user.id) end create_bulk_task(params[:task], @case_note) if params.has_key?(:task) + @case_note.complete_screening_tasks(params) if params[:case_note].has_key?(:tasks_attributes) create_task_task_progress_notes delete_events if session[:authorization] redirect_to client_case_notes_path(@client), notice: t('.successfully_updated') diff --git a/app/controllers/client/tasks_controller.rb b/app/controllers/client/tasks_controller.rb index 381cb807c3..2e080be11b 100644 --- a/app/controllers/client/tasks_controller.rb +++ b/app/controllers/client/tasks_controller.rb @@ -6,7 +6,7 @@ class Client::TasksController < AdminController before_action :find_task, only: [:edit, :update, :destroy] def index - @tasks = @client.tasks.includes(:domain) + @tasks = @client.tasks.includes(:taskable) end def create @@ -99,8 +99,8 @@ def authorize_client def find_calendars(task) task_name = task.name - domain = Domain.find(task.domain_id) - title = "#{domain.name} - #{task_name}" + domain = Domain.find(task.domain_id) if task.domain_id + title = task.domain_id ? "#{domain.name} - #{task_name}" : task_name start_date = task.expected_date end_date = (start_date + 1.day).to_s @calendars = Calendar.where(title: title, start_date: start_date, end_date: end_date) diff --git a/app/controllers/clients_controller.rb b/app/controllers/clients_controller.rb index c141d72a23..0bbfc8cb09 100644 --- a/app/controllers/clients_controller.rb +++ b/app/controllers/clients_controller.rb @@ -8,7 +8,7 @@ class ClientsController < AdminController before_action :assign_active_client_prams, only: :index before_action :format_search_params, only: [:index] before_action :get_quantitative_fields, :get_hotline_fields, :hotline_call_column, only: [:index] - before_action :find_params_advanced_search, :get_custom_form, :get_program_streams, only: [:index] + before_action :find_params_advanced_search, :get_custom_form, :get_program_streams, :get_assessments, only: [:index] before_action :get_custom_form_fields, :program_stream_fields, :custom_form_fields, :client_builder_fields, only: [:index] before_action :basic_params, if: :has_params?, only: [:index] before_action :build_advanced_search, only: [:index] @@ -56,7 +56,7 @@ def show format.html do @referees = Referee.none_anonymouse.pluck(:id, :name).map{|id, name| { value: id, text: name } } @current_provinces = Province.pluck(:id, :name).map{|id, name| { value: id, text: name } } - @birth_provinces = @birth_provinces.map{|parent, children| children.map{|t, v| {value: v, text: t } } }.flatten + @birth_provinces = @birth_provinces.map{|parent, children| children.map{|t, v| { value: v, text: t } } }.flatten custom_field_ids = @client.custom_field_properties.pluck(:custom_field_id) if current_user.admin? || current_user.strategic_overviewer? available_editable_forms = CustomField.all @@ -129,6 +129,8 @@ def new end @client = Client.new(new_params.merge(local_given_name: first_name, local_family_name: last_name, gender: new_params[:gender]&.downcase)) + @risk_assessment = @client.build_risk_assessment + @risk_assessment.tasks.build end end @@ -141,6 +143,8 @@ def edit attributes.merge!({ status: 'Referred' }) @client.attributes = attributes end + + @risk_assessment = @client.risk_assessment || @client.build_risk_assessment end def create @@ -352,7 +356,7 @@ def country_address_fields end def initial_visit_client - referrer = Rails.application.routes.recognize_path(request.referrer) + referrer = Rails.application.routes.recognize_path(request.referrer.gsub(/[a-z]{3,}\-/, '').gsub('/?', '?')) if request.referrer return unless referrer.present? white_list_referrers = %w[clients] diff --git a/app/controllers/concerns/client_advanced_searches_concern.rb b/app/controllers/concerns/client_advanced_searches_concern.rb index 3d195b6fac..b258deb403 100644 --- a/app/controllers/concerns/client_advanced_searches_concern.rb +++ b/app/controllers/concerns/client_advanced_searches_concern.rb @@ -91,7 +91,7 @@ def client_builder_fields @builder_fields = @builder_fields + custom_form_fields if @advanced_search_params[:wizard_custom_form_check].present? @builder_fields = @builder_fields + @quantitative_fields if @advanced_search_params[:wizard_quantitative_check].present? else - @builder_fields = get_client_basic_fields + custom_form_fields + program_stream_fields + @builder_fields = get_client_basic_fields + custom_form_fields + program_stream_fields + get_common_fields @builder_fields = @builder_fields + @quantitative_fields if quantitative_check? end end @@ -108,6 +108,12 @@ def get_client_basic_fields AdvancedSearches::ClientFields.new(user: current_user, pundit_user: pundit_user).render end + def get_common_fields + fields = program_stream_values.empty? ? [] : AdvancedSearches::CommonFields.new(program_stream_values).render + fields += assessment_values.empty? ? [] : AdvancedSearches::CommonFields.new(program_stream_values, true).render + fields + end + def get_hotline_fields args = { translation: get_basic_field_translations, number_field: [], @@ -122,8 +128,8 @@ def get_hotline_fields *get_dropdown_list(['phone_call_id', 'call_type', 'start_datetime', 'protection_concern_id', 'necessity_id']), ] } - hotline_fields = AdvancedSearches::AdvancedSearchFields.new('hotline', args).render - @hotline_fields = get_client_hotline_fields + hotline_fields + hotline_fields = AdvancedSearches::AdvancedSearchFields.new('hotline', args).render + @hotline_fields = get_client_hotline_fields + hotline_fields end def get_client_hotline_fields @@ -143,7 +149,6 @@ def get_client_hotline_fields dropdown_list_option: dropdown_list_options } @client_hotline_fields = AdvancedSearches::AdvancedSearchFields.new('concern_basic_fields', args).render - end def hotline_text_type_list @@ -214,6 +219,18 @@ def quantitative_check? @advanced_search_params.present? && @advanced_search_params[:quantitative_check].present? end + def assessment_value? + @advanced_search_params.present? && @advanced_search_params[:assessment_selected].present? + end + + def assessment_values + assessment_value? ? eval(@advanced_search_params[:assessment_selected]) : [] + end + + def get_assessments + @assessments = (Setting.cache_first.enable_default_assessment? ? [[0, Setting.cache_first.default_assessment]] : []) + CustomAssessmentSetting.all.where(enable_custom_assessment: true).pluck(:id, :custom_assessment_name).to_a + end + def has_params? @advanced_search_params.present? && @advanced_search_params[:basic_rules].present? end diff --git a/app/controllers/concerns/family_advanced_searches_concern.rb b/app/controllers/concerns/family_advanced_searches_concern.rb index 558b801b53..42efd05a51 100644 --- a/app/controllers/concerns/family_advanced_searches_concern.rb +++ b/app/controllers/concerns/family_advanced_searches_concern.rb @@ -78,7 +78,7 @@ def custom_form_values end def custom_form_fields - @custom_form_fields = get_custom_form_fields + get_has_this_form_fields + @custom_form_fields = get_custom_form_fields + get_has_this_form_fields end def get_has_this_form_fields diff --git a/app/controllers/concerns/locale_concern.rb b/app/controllers/concerns/locale_concern.rb new file mode 100644 index 0000000000..1fa501f735 --- /dev/null +++ b/app/controllers/concerns/locale_concern.rb @@ -0,0 +1,20 @@ +module LocaleConcern + def set_locale + local = I18n.locale + local = params[:locale] if params[:locale] && I18n.available_locales.include?(params[:locale].to_sym) + + if detect_browser.present? + flash.clear + flash[:alert] = detect_browser + end + + I18n.locale = local + end + + def detect_browser + lang = params[:locale] || locale.to_s + if browser.firefox? && browser.platform.mac? && lang == 'km' + "Khmer fonts for Firefox do not render correctly. Please use Google Chrome browser instead if you intend to use OSCaR in Khmer language." + end + end +end diff --git a/app/controllers/screening_assessments_controller.rb b/app/controllers/screening_assessments_controller.rb new file mode 100644 index 0000000000..dc5880c21d --- /dev/null +++ b/app/controllers/screening_assessments_controller.rb @@ -0,0 +1,95 @@ +class ScreeningAssessmentsController < AdminController + load_and_authorize_resource params: :screening_assessment_params + before_action :find_screening_assessment, except: [:index, :new, :create] + before_action :find_client + before_action :find_previous_screening_assessment, only: [:new, :create, :edit, :update] + + def index + @screening_assessments = @client.screening_assessments.accessible_by(current_ability) + end + + def new + @screening_assessment = @client.screening_assessments.new + @screening_assessment.populate_developmental_markers + @screening_assessment.tasks.build(name: t('screening_assessments._attr.refer_to_specialist')) + end + + def create + @screening_assessment = @client.screening_assessments.new(screening_assessment_params) + authorize_screening_assessment(@screening_assessment) + if @screening_assessment.save + redirect_to [@client, @screening_assessment], notice: t('successfully_created', klass: 'Screening Assessment') + else + @screening_assessment.populate_developmental_markers + flash[:alert] = @screening_assessment.errors.full_messages.join(', ') + render :new, screening_type: @screening_assessment.screening_type + end + end + + def show + @developmental_marker_screening_assessments = @screening_assessment.developmental_marker_screening_assessments.includes(:developmental_marker) + @tasks = @screening_assessment.tasks + end + + def edit + @developmental_marker_screening_assessments = @screening_assessment.developmental_marker_screening_assessments + maker_name = @screening_assessment.client_milestone_age + @screening_assessment.populate_developmental_markers(maker_name) + @screening_assessment.tasks.build(name: t('screening_assessments._attr.refer_to_specialist')) if @screening_assessment.tasks.blank? + end + + def update + if @screening_assessment.update_attributes(screening_assessment_params) + redirect_to [@client, @screening_assessment], notice: t('successfully_updated', klass: 'Screening Assessment') + else + @screening_assessment.populate_developmental_markers + flash[:alert] = @screening_assessment.errors.full_messages.join(', ') + render :edit + end + end + + def destroy + if @screening_assessment.destroy + redirect_to client_path(@client), notice: t('successfully_deleted', klass: 'Screening Assessment') + else + messages = @screening_assessment.errors.full_messages.uniq.join('\n') + redirect_to [@client, @screening_assessment], alert: messages + end + end + + private + + def authorize_screening_assessment(screening_assessment) + if @client.status == 'Exited' + raise Pundit::NotAuthorizedError + elsif screening_assessment.screening_type == 'one_off' + raise Pundit::NotAuthorizedError unless current_setting.cbdmat_one_off + elsif screening_assessment.screening_type == 'multiple' + raise Pundit::NotAuthorizedError unless current_setting.cbdmat_ongoing + end + end + + def screening_assessment_params + params.require(:screening_assessment).permit( + :screening_assessment_date, :client_age, :visitor, :client_milestone_age, :note, + :smile_back_during_interaction, :follow_object_passed_midline, :turn_head_to_sound, + :head_up_45_degree, :screening_type, :client_id, attachments: [], + developmental_marker_screening_assessments_attributes: [ + :id, :developmental_marker_id, :question_1, :question_2, :question_3, :question_4, :_destroy + ], + tasks_attributes: [:id, :client_id, :name, :expected_date, :completion_date, :taskable_id, :taskable_type, :relation, :_destroy] + ) + end + + def find_screening_assessment + @screening_assessment = ScreeningAssessment.find(params[:id]) + end + + def find_client + @client = Client.friendly.find(params[:client_id]) + end + + def find_previous_screening_assessment + @previous_screening_assessment = ScreeningAssessment.where(client_id: @client.id).where.not(id: @screening_assessment.id).last + end +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index af3afcfed5..2cd785aecc 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,4 +1,5 @@ class SessionsController < Devise::SessionsController + include LocaleConcern before_action :set_whodunnit, :set_current_ngo, :detect_browser after_action :increase_visit_count, only: :create skip_before_action :set_locale, only: :create @@ -15,14 +16,6 @@ def set_current_ngo @current_ngo = Organization.current end - def detect_browser - lang = params[:locale] || locale.to_s - if browser.firefox? && browser.platform.mac? && lang == 'km' - flash.clear - flash[:alert] = "Application is not translated properly for Firefox on Mac, we're sorry to suggest to use Google Chrome browser instead." - end - end - def increase_visit_count Visit.create(user: current_user) end diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index cec606be8a..a7633b3cbd 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -97,6 +97,17 @@ def limit_tracking_form authorize @setting end + def risk_assessment + authorize @setting + attribute = params[:setting] + if attribute && @setting.update_attributes(setting_params) + redirect_to :back, notice: t('successfully_updated', klass: t('settings.update.successfully_updated')) + else + flash[:alert] = @setting.errors.full_messages.join(", ") if @setting.errors.full_messages.any? + render :risk_assessment + end + end + private def redirect_to_default @@ -123,9 +134,10 @@ def setting_params :internal_referral_limit, :internal_referral_frequency, :case_note_edit_limit, :case_note_edit_frequency, :tracking_form_edit_limit, :tracking_form_edit_frequency, :disabled_future_completion_date, :disabled_task_date_field, :disabled_add_service_received, :custom_field_limit, :custom_field_frequency, :test_client, :required_case_note_note, - :hide_case_note_note, + :hide_case_note_note, :cbdmat_one_off, :cbdmat_ongoing, :enabled_risk_assessment, :assessment_type_name, + :level_of_risk_guidance, client_default_columns: [], family_default_columns: [], community_default_columns: [], - partner_default_columns: [], user_default_columns: [], + partner_default_columns: [], user_default_columns: [], selected_domain_ids: [], custom_assessment_settings_attributes: [:id, :custom_assessment_name, :max_custom_assessment, :custom_assessment_frequency, :custom_age, :enable_custom_assessment, :_destroy]) end diff --git a/app/grids/client_grid.rb b/app/grids/client_grid.rb index d2153774ed..8ab34611d5 100644 --- a/app/grids/client_grid.rb +++ b/app/grids/client_grid.rb @@ -1168,9 +1168,9 @@ def call_fields if fields.first == 'formbuilder' if data == 'recent' if fields.last == 'Has This Form' - properties = object.custom_field_properties.cached_client_custom_field_properties_count(fields.second) + properties = object.custom_field_properties.cached_client_custom_field_properties_count(object, fields.second) else - properties = object.custom_field_properties.cached_client_custom_field_properties_order(fields.second) + properties = object.custom_field_properties.cached_client_custom_field_properties_order(object, fields.second) properties = properties[format_field_value] if properties.present? end else @@ -1178,14 +1178,14 @@ def call_fields properties = [custom_form_with_has_form(object, fields).count] else if $param_rules - custom_field_id = object.custom_fields.cached_client_custom_field_find_by(fields.second) + custom_field_id = object.custom_fields.cached_client_custom_field_find_by(object, fields.second) basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access results = mapping_form_builder_param_value(basic_rules, 'formbuilder') query_string = get_query_string(results, 'formbuilder', 'custom_field_properties.properties') sql = query_string.reverse.reject(&:blank?).map{|sql| "(#{sql})" }.join(" AND ") - properties = object.custom_field_properties.cached_client_custom_field_properties_properties_by(custom_field_id, sql, format_field_value) + properties = object.custom_field_properties.cached_client_custom_field_properties_properties_by(object, custom_field_id, sql, format_field_value) properties = properties.blank? ? custom_form_with_has_form(object, fields).properties_by(format_field_value) : properties else properties = form_builder_query(object.custom_field_properties, fields.second, column_builder[:id].gsub('&qoute;', '"'), 'custom_field_properties.properties').properties_by(format_field_value) @@ -1194,24 +1194,24 @@ def call_fields end elsif fields.first == 'enrollmentdate' if data == 'recent' - properties = date_format(object.client_enrollments.cached_client_order_enrollment_date(fields.second)) + properties = date_format(object.client_enrollments.cached_client_order_enrollment_date(object, fields.second)) else - properties = date_filter(object.client_enrollments.cached_client_enrollment_date_join(fields.second), fields.join('__')).map{|date| date_format(date.enrollment_date) } + properties = date_filter(object.client_enrollments.cached_client_enrollment_date_join(object, fields.second), fields.join('__')).map{|date| date_format(date.enrollment_date) } end elsif fields.first == 'enrollment' if data == 'recent' - properties = object.client_enrollments.cached_client_order_enrollment_date_properties(fields.second) + properties = object.client_enrollments.cached_client_order_enrollment_date_properties(object, fields.second) properties = properties[format_field_value] if properties.present? else - properties = object.client_enrollments.cached_client_enrollment_date_join(fields.second).properties_by(format_field_value) + properties = object.client_enrollments.cached_client_enrollment_date_join(object, fields.second).properties_by(format_field_value) end elsif fields.first == 'tracking' ids = object.client_enrollments.ids if data == 'recent' - properties = ClientEnrollmentTracking.cached_tracking_order_created_at(fields.third, ids) + properties = ClientEnrollmentTracking.cached_tracking_order_created_at(object, fields.third, ids) properties = properties[format_field_value] if properties.present? else - client_enrollment_trackings = ClientEnrollmentTracking.cached_client_enrollment_tracking(fields.third, ids) + client_enrollment_trackings = ClientEnrollmentTracking.cached_client_enrollment_tracking(object, fields.third, ids) properties = form_builder_query(client_enrollment_trackings, fields.first, column_builder[:id].gsub('&qoute;', '"')).properties_by(format_field_value, client_enrollment_trackings) end elsif fields.first == 'exitprogramdate' diff --git a/app/grids/family_grid.rb b/app/grids/family_grid.rb index 09853fcf8f..b5f4f40ee6 100644 --- a/app/grids/family_grid.rb +++ b/app/grids/family_grid.rb @@ -5,7 +5,7 @@ class FamilyGrid < BaseGrid attr_accessor :dynamic_columns scope do - Family.includes({cases: [:client]}, :village, :commune, :district, :province).order(:name) + Family.order(:name) end filter(:name, :string, header: -> { I18n.t('datagrid.columns.families.name') }) do |value, scope| @@ -78,19 +78,19 @@ def created_by end def commune_options - Family.joins(:commune).map{|f| [f.commune.code_format, f.commune_id]}.uniq + scope.includes(:commune).references(:communes).map{|f| next unless f.commune; [f.commune.code_format, f.commune_id]}.uniq end def village_options - Family.joins(:village).map{|f| [f.village.code_format, f.village_id]}.uniq + scope.includes(:village).references(:villages).map{|f| next unless f.village; [f.village.code_format, f.village_id]}.uniq end def province_options - Family.province_are + scope.province_are end def district_options - Family.joins(:district).pluck('districts.name', 'districts.id').uniq + scope.includes(:district).references(:districts).pluck('districts.name', 'districts.id').uniq end def gender_options @@ -343,19 +343,19 @@ def filer_section(filter_name) column(:phone_number, header: -> { I18n.t('datagrid.columns.families.phone_number') }) column(:street, header: -> { I18n.t('datagrid.columns.families.street') }) - column(:village_id, order: 'villages.name_kh', header: -> { I18n.t('datagrid.columns.families.village') }) do |object| + column(:village_id, preload: proc { |f| f.includes(:village) }, order: 'villages.name_kh', header: -> { I18n.t('datagrid.columns.families.village') }) do |object| format(object.village.try(:code_format)) { |value| value } end - column(:commune_id, order: 'communes.name_kh', header: -> { I18n.t('datagrid.columns.families.commune') }) do |object| + column(:commune_id, preload: proc { |f| f.includes(:commune) }, order: 'communes.name_kh', header: -> { I18n.t('datagrid.columns.families.commune') }) do |object| format(object.commune.try(:name)) { |value| value } end - column(:district_id, order: 'districts.name', header: -> { I18n.t('datagrid.columns.families.district') }) do |object| + column(:district_id, preload: proc { |f| f.includes(:district) }, order: 'districts.name', header: -> { I18n.t('datagrid.columns.families.district') }) do |object| format(object.district_name) { |value| value } end - column(:province_id, order: 'provinces.name', header: -> { I18n.t('datagrid.columns.families.province') }) do |object| + column(:province_id, preload: proc { |f| f.includes(:province) }, order: 'provinces.name', header: -> { I18n.t('datagrid.columns.families.province') }) do |object| format(object.province_name) { |value| value } end @@ -450,7 +450,7 @@ def filer_section(filter_name) dynamic do quantitative_type_readable_ids = current_user.quantitative_type_permissions.readable.pluck(:quantitative_type_id) unless current_user.nil? - + QuantitativeType.cach_free_text_fields_by_visible_on('family').each do |qqt_free_text| if current_user.nil? || quantitative_type_readable_ids.include?(qqt_free_text.id) column(qqt_free_text.name.to_sym, class: 'quantitative-type', header: -> { qqt_free_text.name }, html: true) do |object| diff --git a/app/helpers/advanced_search_helper.rb b/app/helpers/advanced_search_helper.rb index 597e560963..635a1d4df9 100644 --- a/app/helpers/advanced_search_helper.rb +++ b/app/helpers/advanced_search_helper.rb @@ -15,6 +15,11 @@ def program_stream_values(report_builder = '#builder') has_program_selected ? eval(advanced_search_params[:program_selected]) : [] end + def assessment_values(report_builder = '#builder') + has_assessment_selected = has_advanced_search? && advanced_search_params[:assessment_selected].present? && (advanced_search_params[:action_report_builder].present? ? report_builder == advanced_search_params[:action_report_builder] : true) + has_assessment_selected ? eval(advanced_search_params[:assessment_selected]) : [] + end + def quantitative_check has_advanced_search? && advanced_search_params[:quantitative_check].present? ? true : false end @@ -169,13 +174,25 @@ def format_header(key, group_name = 'client') type_of_service: I18n.t('advanced_search.fields.type_of_service'), hotline: I18n.t('datagrid.columns.calls.hotline'), active_clients: I18n.t('advanced_search.fields.active_clients'), + active_client_program: I18n.t('advanced_search.fields.active_client_program'), care_plan: I18n.t('advanced_search.fields.care_plan'), arrival_at: I18n.t('clients.form.arrival_at'), flight_nb: I18n.t('clients.form.flight_nb'), ratanak_achievement_program_staff_client_ids: I18n.t('clients.form.ratanak_achievement_program_staff_client_ids'), mo_savy_officials: I18n.t('clients.form.mosavy_official'), **overdue_translations, - **address_translation(group_name) + **address_translation(group_name), + number_client_referred_gatekeeping: I18n.t('advanced_search.fields.number_client_referred_gatekeeping'), + number_client_billable: I18n.t('advanced_search.fields.number_client_billable'), + assessment_condition_last_two: I18n.t('advanced_search.fields.assessment_condition_last_two'), + assessment_condition_first_last: I18n.t('advanced_search.fields.assessment_condition_first_last'), + client_rejected: I18n.t('advanced_search.fields.client_rejected'), + incomplete_care_plan: I18n.t('advanced_search.fields.incomplete_care_plan'), + case_history: I18n.t('default_family_fields.case_history'), + family: I18n.t('advanced_search.fields.family'), + case_note: I18n.t('dashboards.case_note_tab.case_note'), + other: I18n.t('advanced_search.fields.other'), + common_searches: I18n.t('advanced_search.fields.common_searches') } translations = label_translations(address_translation(group_name)).merge(translations) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ec6fd535bf..5fd67f3efb 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -192,6 +192,8 @@ def date_format(date) end def date_time_format(date_time) + return if date_time.nil? + date_time.in_time_zone('Bangkok').strftime('%d %B %Y %I:%M%p') end @@ -326,8 +328,8 @@ def forms_notification_label end end - def whodunnit(type, id) - user_id = PaperTrail::Version.find_by(event: 'create', item_type: type, item_id: id).try(:whodunnit) + def whodunnit(type, id, event='create') + user_id = PaperTrail::Version.find_by(event: event, item_type: type, item_id: id).try(:whodunnit) if user_id.blank? || (user_id.present? && user_id.include?('@rotati')) object = type.constantize.find(id) user_id = object.has_attribute?(:user_id) ? object&.user_id : object.try(:parent)&.user_id @@ -337,7 +339,11 @@ def whodunnit(type, id) end end - User.find_by(id: user_id).try(:name) || '' + made_changed_by(user_id) + end + + def made_changed_by(user_id) + User.find_by(id: user_id).try(:name) || 'User not found' end def khmer_dob_to_age(date) @@ -454,4 +460,9 @@ def request_method (['clients', 'families'].include?(params[:controller]) && params[:action] == 'index') ? 'Post' : 'Get' end + def age_in_hash(dob) + now = Time.now.utc + distance_of_time_in_words_hash(now, dob) + end + end diff --git a/app/helpers/assessment_helper.rb b/app/helpers/assessment_helper.rb index 1754202d71..8f17ce54d4 100644 --- a/app/helpers/assessment_helper.rb +++ b/app/helpers/assessment_helper.rb @@ -112,10 +112,10 @@ def assess_header_mapping(default=true) domains = default ? Domain.csi_domains.map{ |domain| ["domain_#{domain.id}", domain.name] } : Domain.custom_csi_domains.map{ |domain| ["domain_#{domain.id}", domain.name] } domain_ids, domain_headers = domains.map(&:first), domains.map(&:last) - assessment_headers = [t('.client_id'), t('.client_name'), t('.assessment_number', assessment: t('clients.show.assessment')), t('.assessment_date', assessment: t('clients.show.assessment'))] + assessment_headers = [t('.client_id'), t('.client_name'), t('.assessment_number', assessment: t('clients.show.assessment')), t('.assessment_date', assessment: t('clients.show.assessment')), t('.average_score', assessment: t('clients.show.assessment'))] - assessment_domain_headers = ['slug', 'name', 'assessment-number', 'date'] - classNames = ['client-id', 'client-name', 'ssessment-number text-center', 'assessment-date', 'assessment-score text-center'] + assessment_domain_headers = ['slug', 'name', 'assessment-number', 'date', 'average-score'] + classNames = ['client-id', 'client-name', 'assessment-number text-center', 'assessment-date', 'average-score text-center', 'assessment-score text-center'] [*assessment_domain_headers, *domain_ids].zip(classNames, [*assessment_headers, *domain_headers]).map do |field_header, class_name, header_name| { title: header_name, data: field_header, className: class_name ? class_name : 'assessment-score text-center' } @@ -354,5 +354,13 @@ def check_assessment_domain_exist?(assessment) end end + def calculate_domain_selected_domain_score(assessment) + sum = assessment.assessment_domains.inject(0) do |sum, ad| + sum + (current_setting.selected_domain_ids.compact.include?(ad.domain_id) && ad.score.present? ? ad.score : 0) + end + + return sum if sum.zero? + (sum.to_f / current_setting.selected_domain_ids.compact.size).round + end end diff --git a/app/helpers/cache_helper.rb b/app/helpers/cache_helper.rb index 3930dd8d3a..73161217cb 100644 --- a/app/helpers/cache_helper.rb +++ b/app/helpers/cache_helper.rb @@ -14,4 +14,4 @@ def setting_cache_key def custom_fields_cache [Apartment::Tenant.current, 'custom_fields'] end -end \ No newline at end of file +end diff --git a/app/helpers/care_plan_helper.rb b/app/helpers/care_plan_helper.rb index d173fc5400..5e0469c4f0 100644 --- a/app/helpers/care_plan_helper.rb +++ b/app/helpers/care_plan_helper.rb @@ -67,6 +67,8 @@ def grid_object end def list_case_conference_domain_for_care_plan(assessment, ad) + return [] if assessment.case_conference.blank? + assessment.case_conference.case_conference_domains.find_by(domain_id: ad.object.domain_id).try(:case_conference_addressed_issues) || [] end diff --git a/app/helpers/clients_helper.rb b/app/helpers/clients_helper.rb index 84591894a5..eb69c3c01a 100644 --- a/app/helpers/clients_helper.rb +++ b/app/helpers/clients_helper.rb @@ -1,4 +1,57 @@ module ClientsHelper + include RiskAssessmentHelper + + def client_form_data + { + translation: rails_i18n_translations, inlineHelpTranslation: JSON.parse(I18n.t('inline_help').to_json), + internationalReferredClient: international_referred_client, selectedCountry: selected_country, + client: + { + client: @client, ratanak_achievement_program_staff_client_ids: @client.ratanak_achievement_program_staff_client_ids, + user_ids: @client.user_ids, quantitative_case_ids: @client.quantitative_case_ids, agency_ids: @client.agency_ids, + donor_ids: @client.donor_ids, isTestClient: current_setting.test_client?, isForTesting: @client.for_testing? + }, + client_quantitative_free_text_cases: get_or_build_client_quantitative_free_text_cases, + family_member: (@client.family_member || {}), moSAVYOfficials: @client.mo_savy_officials, + referee: @referee.as_json(methods: [:existing_referree]), carer: @carer , users: case_workers_option(@client.id), + referralSourceCategory: @referral_source_category, referralSource: ReferralSource.all, birthProvinces: @birth_provinces, + currentProvinces: @current_provinces || get_address('province'), districts: @districts.presence || get_address('district'), + subDistricts: @subdistricts, communes: @communes.presence || get_address('commune'), villages: @villages.presence || get_address('village'), + currentStates: @states, currentTownships: @townships, refereeTownships: @referee_townships, carerTownships: @carer_townships, + refereeDistricts: @referee_districts, refereeSubdistricts: @referee_subdistricts, refereeCommunes: @referee_communes, + refereeVillages: @referee_villages, carerDistricts: @carer_districts, carerSubdistricts: @carer_subdistricts, carerCommunes: @carer_communes, + carerVillages: @carer_villages, donors: @donors, agencies: @agencies, + quantitativeType: QuantitativeType.cach_by_visible_on('client'), quantitativeCase: QuantitativeCase.cache_all, + ratePoor: [ + t('clients.level').values, Client::CLIENT_LEVELS + ].transpose, + schoolGrade: [ + Client::GRADES, t('advanced_search.fields.school_grade_list').values + ].transpose, + families: @families, refereeRelationships: @referee_relationships, + clientRelationships: @client_relationships, callerRelationships: @caller_relationships, + addressTypes: @address_types, phoneOwners: @phone_owners, fieldsVisibility: fields_visibility, + requiredFields: required_legal_docs, current_organization: JSON.parse(current_organization.to_json), + brc_address: get_address_json, maritalStatuses: Client::MARITAL_STATUSES, nationalities: Client::NATIONALITIES, + ethnicities: Client::ETHNICITY, traffickingTypes: Client::TRAFFICKING_TYPES, brc_islands: Client::BRC_BRANCHES, + brc_resident_types: Client::BRC_RESIDENT_TYPES, brc_presented_ids: Client::BRC_PRESENTED_IDS, + brc_prefered_langs: Client::BRC_PREFERED_LANGS, customId1: custom_id_translation('custom_id1'), + customId2: custom_id_translation('custom_id2'), referees: Referee.where(anonymous: false), + protectionConcerns: I18n.locale == :km ? protection_concern_list_local : protection_concern_list, + historyOfHarms: history_of_harms, historyOfHighRiskBehaviours: history_of_high_risk_behaviours, + reasonForFamilySeparations: reason_for_family_separations, historyOfDisabilities: history_of_disabilities, + isRiskAssessmentEnabled: current_setting.enabled_risk_assessment, + riskAssessment: { + **@risk_assessment.try(:attributes).try(:symbolize_keys) || {}, + labels: { + **I18n.t('risk_assessments._attr'), + **I18n.t('tasks') + }, + tasks_attributes: @risk_assessment.try(:tasks) || [] + } + } + end + def get_or_build_client_quantitative_free_text_cases QuantitativeType.where(field_type: 'free_text').map do |qtt| @client.client_quantitative_free_text_cases.find_or_initialize_by(quantitative_type_id: qtt.id) @@ -1419,4 +1472,19 @@ def saved_search_column_visibility(field_key) def legal_doc_fields FieldSetting.cache_legal_doc_fields end + + def if_date_of_birth_blank(client) + return '#screening-tool-warning' if client.date_of_birth.blank? + screening_assessment = @client.screening_assessments.first + if screening_assessment && screening_assessment.screening_type == 'one_off' + client_screening_assessment_path(client, screening_assessment) + else + new_client_screening_assessment_path(client, screening_type: 'one_off') + end + end + + def has_of_warning_model_if_dob_blank(client) + return { "data-target": "#screening-tool-warning", "data-toggle": "modal" } if client.date_of_birth.blank? + {} + end end diff --git a/app/helpers/domain_helper.rb b/app/helpers/domain_helper.rb index 0c06527677..963e287639 100644 --- a/app/helpers/domain_helper.rb +++ b/app/helpers/domain_helper.rb @@ -1,9 +1,17 @@ module DomainHelper def translate_domain_header(domain) if I18n.locale == :km - domain.local_description[/.*<\/strong>/].html_safe + domain.local_description[/.*<\/strong>/].try(:html_safe) || "#{t('domains.domain_list.domains')} : #{domain.name} (#{domain.identity})" else - "#{t('.domains')} : #{domain.name} (#{domain.identity})" + "#{t('domains.domain_list.domains')} : #{domain.name} (#{domain.identity})" end end + + def mapping_domain_name_and_identity(domains) + domains.map{ |domain| [translate_domain_header(domain), domain.id] } + end + + def custom_domain_groups + Domain.custom_csi_domains.group_by { |domain| domain.custom_assessment_setting_id } + end end diff --git a/app/helpers/risk_assessment_helper.rb b/app/helpers/risk_assessment_helper.rb new file mode 100644 index 0000000000..48b181e986 --- /dev/null +++ b/app/helpers/risk_assessment_helper.rb @@ -0,0 +1,195 @@ +module RiskAssessmentHelper + def at_risk_en + [ + 'At risk of neglect', + 'At risk of sexual exploitation', + 'At risk of online sexual exploitation', + 'At risk of substance abuse', + 'At risk of child kidnapping', + 'At risk of trafficking', + 'At risk of physical violence', + 'At risk of emotional violence', + 'At risk of sexual violence', + 'At risk of forced/child marriage', + 'At risk of child labour', + 'At risk of worst forms of child labour' + ] + end + + def at_risk_km + [ + 'ប្រឈមនឹងការមិនអើពើ', + 'ប្រឈមនឹងការកេងប្រវ័ញ្ចផ្លូវភេទ', + 'ប្រឈមនឹងការកេងប្រវ័ញ្ចផ្លូវភេទតាមប្រព័ន្ធអ៊ីនធរនេត', + 'ប្រឈមនឹងការញៀន', + 'ប្រឈមនឹងការចាប់ពង្រត់កុមារ', + 'ប្រឈមនឹងការជួញដូរ', + 'ប្រឈមនឹងអំពើហឹង្សាផ្លូវកាយ', + 'ប្រឈមនឹងអំពើហឹង្សាផ្លូវចិត្ត', + 'ប្រឈមអំពើហឹង្សាផ្លូវភេទ', + 'ប្រឈមនឹងការរៀបអាពាហ៍ពិពាហ៍កុមារ/បង្ខំ', + 'ប្រឈមនឹងពលកម្មកុមារ', + 'ប្រឈមនឹងទម្រង់ធ្ងន់ធ្ងរបំផុតនៃពលកម្មកុមារ' + ] + end + + def experiencing_en + [ + 'Experiencing neglect', + 'Experiencing sexual exploitation', + 'Experiencing online sexual exploitation', + 'Experiencing substance abuse', + 'Experiencing child kidnapping', + 'Experienced trafficking', + 'Experiencing physical violence', + 'Experiencing emotional violence', + 'Experienced sexual violence', + 'Experienced forced/child marriage', + 'Experiencing child labour', + 'Experiencing worst forms of child labour' + ] + end + + def experiencing_km + [ + 'ទទួលរងការមិនអើពើ', + 'ទទួលរងការកេងប្រវ័ញ្ចផ្លូវភេទ', + 'ទទួលរងការកេងប្រវ័ញ្ចផ្លូវភេទតាមប្រព័ន្ធអ៊ីនធរនេត', + 'ទទួលរងការញៀន', + 'ទទួលរងការចាប់ពង្រត់កុមារ', + 'ទទួលរងការជួញដូរ', + 'ទទួលរងអំពើហឹង្សាផ្លូវកាយ', + 'ទទួលរងអំពើហឹង្សាផ្លូវចិត្ត', + 'ទទួលរងអំពើហឹង្សាផ្លូវភេទ', + 'ទទួលរងការរៀបអាពាហ៍ពិពាហ៍កុមារ/បង្ខំ', + 'ទទួលរងពលកម្មកុមារ', + 'ទទួលរងទម្រង់ធ្ងន់ធ្ងរបំផុតនៃពលកម្មកុមារ' + ] + end + + def other_form_en + [ + 'Abandonment', + 'Separated', + 'Orphaned', + 'Unaccompanied', + 'In conflict with law', + 'Minority / Isolated community', + 'Delinquent behaviour', + 'Stigmatization', + 'Working or living on street', + 'Witness of violence', + 'Gambling issues', + 'Affected by migration', + 'Infected by COVID-19', + 'Affected by COVID-19', + 'Other' + ] + end + + def other_form_km + [ + 'ត្រូវបានបោះបង់ចោល', + 'បានបែកចេញ', + 'កំព្រា', + 'គ្មានមនុស្សពេញវ័យនៅជាមួយ', + 'មានទំនាស់នឹងច្បាប់', + 'ជនជាតិភាគតិច/សហគមន៍ឯកោ', + 'ឥរិយាបថទំនើង (ប្រព្រឹត្តខុសច្បាប់)', + 'រងការរើសអើង', + 'ធ្វើការ ឬរស់នៅតាមចិញ្ជើមផ្លូវ', + 'សាក្សីនៃអំពើហឹង្សា', + 'បញ្ហាល្បែងស៊ីសង', + 'ប៉ះពាល់ដោយចំណាកស្រុក', + 'ឆ្លងជង្ងឺកូវីដ-19', + 'ទទួលរងផលប៉ះពាល់ពីជម្ងឺកូវីដ-១៩', + 'បញ្ហាផ្សេងៗ' + ] + end + + def protection_concern_list + [ + { + label: 'At risk', + options: at_risk_en.zip(at_risk_en).map{ |k, v| { label: k, value: v } } + }, + { + label: 'Experiencing/Experienced', + options: experiencing_en.zip(experiencing_en).map{ |k, v| { label: k, value: v } } + }, + { + label: 'Other Form', + options: other_form_en.zip(other_form_en).map{ |k, v| { label: k, value: v } } + } + ] + end + + def protection_concern_list_local + [ + { + label: 'ការប្រឈម', + options: at_risk_km.zip(at_risk_en).map{ |k, v| { label: k, value: v } } + }, + { + label: 'ទទួលរង/ធ្លាប់ឆ្លងកាត់', + options: experiencing_km.zip(experiencing_en).map{ |k, v| { label: k, value: v } } + }, + { + label: 'ទម្រង់ផ្សេងៗ', + options: other_form_km.zip(other_form_en).map{ |k, v| { label: k, value: v } } + } + ] + end + + def select_quantitative_type(value) + quantitative_types = QuantitativeType.cach_by_visible_on('client') + quantitative_type = quantitative_types.select{|qt| qt.name =~ /#{value}/ }.first + return [] if quantitative_type.blank? + + quantitative_cases = select_quantitative_cases(quantitative_type.id) + quantitative_cases.map { |quantitative_case| [quantitative_case.value, quantitative_case.id] } + .map { |value, id| { label: split_quantitative_case_value(value), value: id } } + end + + def split_quantitative_case_value(quantitative_case_value) + values = quantitative_case_value.split(' / ') + I18n.locale == :km ? values.first : values.last + end + + def select_quantitative_cases(quantitative_type_id) + QuantitativeCase.cache_all.select{ |qc| qc.quantitative_type_id == quantitative_type_id } + end + + def history_of_harms + select_quantitative_type('History of Harm') + end + + def history_of_high_risk_behaviours + select_quantitative_type('History of high-risk behaviours') + end + + def reason_for_family_separations + select_quantitative_type('Reason for Family Separation') + end + + def history_of_disabilities + select_quantitative_type('History of disability') + end + + def display_level_of_risk(level_of_risk) + return '' unless level_of_risk + color_hash = {'high' => 'danger', 'medium' => 'warning', 'low' => 'primary', 'no action' => 'success', 'pending_assessment' => 'default' } + content_tag(:a, class: "btn btn-#{color_hash[level_of_risk]}") do + level_of_risk.titleize + end + end + + def level_of_risk_options + [ + I18n.t('risk_assessments._attr.level_of_risks.high'), + I18n.t('risk_assessments._attr.level_of_risks.medium'), + I18n.t('risk_assessments._attr.level_of_risks.low'), + I18n.t('risk_assessments._attr.level_of_risks.no_action') + ].zip(['high', 'medium', 'low', 'no action']) + end +end diff --git a/app/helpers/screening_assessment_helper.rb b/app/helpers/screening_assessment_helper.rb new file mode 100644 index 0000000000..37d9fc01bf --- /dev/null +++ b/app/helpers/screening_assessment_helper.rb @@ -0,0 +1,19 @@ +module ScreeningAssessmentHelper + def field_to_local(object, field_name) + if I18n.locale == :km + object.public_send("#{field_name}_local") + else + object.public_send(field_name) + end + end + + def date_of_birth_in_words(date_of_birth, locale = :en) + if date_of_birth.present? + age_hash = age_in_hash(date_of_birth) + age_in_words = time_ago_in_words(date_of_birth, include_seconds: false, locale: locale) + age_in_words.gsub(/,\s\d+\s(hour(s)?.*|ម៉ោង.*)/, '') + else + "No Date of Birth" + end + end +end diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index ffbedbaf46..efd6e0216a 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -1,2 +1,9 @@ module SettingsHelper + def collect_assessment_types + assessment_types = current_setting.enable_default_assessment ? [[I18n.t('risk_assessments._attr.client_status_index'), 'csi']] : [] + CustomAssessmentSetting.only_enable_custom_assessment.pluck(:custom_assessment_name, :id).each do |arr| + assessment_types << arr + end + assessment_types + end end diff --git a/app/javascript/components/Commons/inputs/dateTimePicker.js b/app/javascript/components/Commons/inputs/dateTimePicker.js index b0bfbe2153..f2e2a4ac7a 100644 --- a/app/javascript/components/Commons/inputs/dateTimePicker.js +++ b/app/javascript/components/Commons/inputs/dateTimePicker.js @@ -24,6 +24,8 @@ export default ({isError, required, label, onChange, value, T }) => { {label} { { existingFiles.length > 0 && showFilePond &&
    - { renderExistingFiles(existingFiles) } + {/* { renderExistingFiles(existingFiles) } */}
    { { const { onChange, options, inline, value, isError, required, disabled } = props - + const [values, setValue] = useState(value) const handleOnChange = event => { + setValue(event.value) onChange({ data: event.value, type: 'radio' }) } @@ -24,7 +25,7 @@ export default props => { disabled={disabled} required value={option.value} - checked={option.value === value} + checked={option.value === values} onChange={handleOnChange} /> {option.label} @@ -64,4 +65,4 @@ const customError = { errorText: { color: 'red' } -} \ No newline at end of file +} diff --git a/app/javascript/components/Commons/inputs/select.js b/app/javascript/components/Commons/inputs/select.js index cc8ef28744..bdf084fdb4 100644 --- a/app/javascript/components/Commons/inputs/select.js +++ b/app/javascript/components/Commons/inputs/select.js @@ -1,8 +1,9 @@ -import React from 'react' +import React, { useEffect, useState } from 'react'; import Select from 'react-select' export default props => { - const { value, options, isMulti, isError, label, required, onChange, asGroup, T, hintText, inlineClassName, ...others } = props + const { value, options, isMulti, isError, label, required, onChange, asGroup, T, hintText, inlineClassName, inline, ...others } = props + const [selectedOption, setSelectedOption] = useState(null); const getSeletedObject = () => { if(options) { @@ -21,6 +22,10 @@ export default props => { } } + useEffect(() => { + setSelectedOption(getSeletedObject()) + }, []); + const handleChange = (selectedOption, { action, removedValue }) => { let data let removed = removedValue && removedValue.value @@ -41,6 +46,7 @@ export default props => { data = action === 'clear' ? null : selectedOption.value } + setSelectedOption(selectedOption) onChange({ data, removed, action, type: 'select', options: options, isMulti: isMulti }) } @@ -51,50 +57,55 @@ export default props => { ) return ( -
    - - { - inlineClassName && - hintText && - - - - } - !v.isFixed)} + defaultValue={selectedOption} + onChange={handleChange} + formatGroupLabel={asGroup && formatGroupLabel} + value={selectedOption} + options={options} + { ...others } + styles={ + Object.assign({}, + customStyles, + isError && customError + ) + } + theme={theme => ({ + ...theme, + colors: { + ...theme.colors, + primary50: '#1ab394', + primary25: '#1ab394', + primary: '#1ab394', + }, + })} + /> + {isError && {T.translate("validation.cannot_blank")} } +
    ) } diff --git a/app/javascript/components/Commons/inputs/text.js b/app/javascript/components/Commons/inputs/text.js index 81eb78918a..1343c0b929 100644 --- a/app/javascript/components/Commons/inputs/text.js +++ b/app/javascript/components/Commons/inputs/text.js @@ -1,10 +1,16 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' export default props => { - const { isError, label, required, onChange, value, hintText, errorText, T, inlineClassName, ...others } = props + const { isError, label, required, onChange, value, hintText, errorText, T, inlineClassName, inline, ...others } = props + const [newValue, setNewValue] = useState(value) + + const handleOnChange = (e) => { + setNewValue(e.target.value) + onChange(e) + } return ( -
    +