From 08d2bd98309c48d0b175a30904ffbc95c288425b Mon Sep 17 00:00:00 2001 From: firelemons Date: Sun, 8 Oct 2023 12:55:07 -0500 Subject: [PATCH 01/49] fix logging level for error --- app/javascript/src/reimbursements.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/src/reimbursements.js b/app/javascript/src/reimbursements.js index 5689f9523e..8732858024 100644 --- a/app/javascript/src/reimbursements.js +++ b/app/javascript/src/reimbursements.js @@ -60,7 +60,7 @@ $(() => { // JQuery's callback for the DOM loading contentType: 'application/json' }).then(() => reimbursementsTable.draw()) } catch (error) { - console.log(error) + console.error(error) event.target.checked = !event.target.checked window.alert('Failed to update reimbursement complete setting') } From 9031e769b97f2c5497c94094024f6ff4acbf7400 Mon Sep 17 00:00:00 2001 From: firelemons Date: Sun, 8 Oct 2023 12:55:50 -0500 Subject: [PATCH 02/49] remove leftover debug prints --- app/javascript/src/reimbursements.js | 1 - app/javascript/src/sms_reactivation_toggle.js | 1 - 2 files changed, 2 deletions(-) diff --git a/app/javascript/src/reimbursements.js b/app/javascript/src/reimbursements.js index 8732858024..4a70edde28 100644 --- a/app/javascript/src/reimbursements.js +++ b/app/javascript/src/reimbursements.js @@ -81,7 +81,6 @@ $(() => { // JQuery's callback for the DOM loading if (e.status === 401) { window.location.reload() } else { - console.log(e) if (e.responseJSON && e.responseJSON.error) { window.alert(e.responseJSON.error) } else { diff --git a/app/javascript/src/sms_reactivation_toggle.js b/app/javascript/src/sms_reactivation_toggle.js index a9c8497991..cc5d545c0e 100644 --- a/app/javascript/src/sms_reactivation_toggle.js +++ b/app/javascript/src/sms_reactivation_toggle.js @@ -9,7 +9,6 @@ $(() => { // JQuery's callback for the DOM loading $('#twilio_disabled').on('click', function (event) { event.preventDefault() - console.log('tooltip?') }) } }) From ffa8b960df6db3e9a348f75cd92c321f59ac4f66 Mon Sep 17 00:00:00 2001 From: firelemons Date: Fri, 13 Oct 2023 01:17:25 -0500 Subject: [PATCH 03/49] created base validatable component, created date picker with range validatable component --- app/javascript/src/case_contact.js | 4 +- app/javascript/src/validated_form.js | 134 +++++++++++++++++++++---- app/views/case_contacts/_form.html.erb | 8 +- 3 files changed, 120 insertions(+), 26 deletions(-) diff --git a/app/javascript/src/case_contact.js b/app/javascript/src/case_contact.js index 7ab3a8e8ed..0d7e6973aa 100644 --- a/app/javascript/src/case_contact.js +++ b/app/javascript/src/case_contact.js @@ -6,7 +6,7 @@ import { escape } from 'lodash' import Swal from 'sweetalert2' function validateOccurredAt (caseOccurredAt, eventType = '') { - const msg = 'Case Contact Occurrences cannot be in the future.' + /* const msg = 'Case Contact Occurrences cannot be in the future.' const today = new Date() today.setHours(0, 0, 0, 0) @@ -19,7 +19,7 @@ function validateOccurredAt (caseOccurredAt, eventType = '') { alert(msg) } caseOccurredAt.val(enGBDateString(today)) - } + } */ } function enGBDateString (date) { diff --git a/app/javascript/src/validated_form.js b/app/javascript/src/validated_form.js index afef65ce10..f11648678f 100644 --- a/app/javascript/src/validated_form.js +++ b/app/javascript/src/validated_form.js @@ -1,30 +1,124 @@ /* global $ */ -$(() => { // JQuery's callback for the DOM loading - const validatedFormCollection = $('.component-validated-form') +const { Notifier } = require('./notifier') +const TypeChecker = require('./type_checker') - validatedFormCollection.on('submit', function (e) { - const form = $(this) - let valid = true +// Abstract Class +class ValidatableFormSectionComponent { + constructor (componentElementsAsJQuery, notifier) { + TypeChecker.checkNonEmptyJQueryObject(componentElementsAsJQuery, 'componentElementsAsJQuery') + + if (!(notifier instanceof Notifier)) { + console.error('Warning: unable to show notifications to the user') + } else { + this.notifier = notifier + } + + this.componentElementsAsJQuery = componentElementsAsJQuery + } + + clearUserError () { + throw new ReferenceError('clearUserError for the component is not defined') + } + + // @param {string} errorState The value returned by getErrorState() + errorHighlightUI (errorState) { + throw new ReferenceError('errorHighlightUI for the component is not defined') + } + + // @returns A string describing the invalid state of the inputs for the user to read, empty string if the inputs are valid + getErrorState () { + throw new ReferenceError('getErrorState for the component is not defined') + } + + notifyUserOfError (errorMsg) { + throw new ReferenceError('notifyUserOfError for the component is not defined') + } + + validate () { + const errorState = this.getErrorState() + + if (errorState) { + this.notifyUserOfError(errorState) + } else { + this.clearUserError() + } + + this.errorHighlightUI(errorState) + return errorState + } +} + +class RangedDatePicker extends ValidatableFormSectionComponent { + constructor (componentElementsAsJQuery, notifier) { + super(componentElementsAsJQuery, notifier) + + const maxDateValue = this.componentElementsAsJQuery.attr('data-max-date') + const minDateValue = this.componentElementsAsJQuery.attr('data-min-date') + this.name = this.componentElementsAsJQuery.attr('component-name') - form.find('.component-date-picker-range').each(function () { - const thisDatePickerRangeAsJQuery = $(this) - const maxDateValue = thisDatePickerRangeAsJQuery.attr('data-max-date') - const minDateValue = thisDatePickerRangeAsJQuery.attr('data-min-date') + this.max = maxDateValue === 'today' ? new Date() : new Date(maxDateValue) + this.min = minDateValue === 'today' ? new Date() : new Date(minDateValue) + } - const max = maxDateValue === 'today' ? new Date() : new Date(maxDateValue) - const min = minDateValue === 'today' ? new Date() : new Date(minDateValue) + clearUserError () { + if (this.errorNotification) { + this.errorNotification.dismiss() + this.errorNotification = undefined + } + } + + errorHighlightUI (errorState) { + if (errorState) { + this.componentElementsAsJQuery.css('border', '2px solid red') + } else { + this.componentElementsAsJQuery.css('border', '') + } + } + + getErrorState () { + const setDate = new Date(this.componentElementsAsJQuery.val()) + const { max, min } = this + + if (setDate > max && !isNaN(max)) { + return `Date for ${this.name} is past maximum allowed date of ${max.toDateString()}` + } else if (setDate < min && !isNaN(min)) { + return `Date for ${this.name} is behind minimum allowed date of ${min.toDateString()}` + } + } + + notifyUserOfError (errorMsg) { + TypeChecker.checkNonEmptyString(errorMsg, 'errorMsg') + + if (this.errorNotification) { + this.errorNotification.setText(errorMsg) + } else if (this.notifier) { + this.errorNotification = this.notifier.notify(errorMsg, 'error', false) + } + } +} + +$(() => { // JQuery's callback for the DOM loading + const notificationsElement = $('#notifications') + const pageNotifier = notificationsElement.length ? new Notifier(notificationsElement) : null + + const validatedFormCollection = $('.component-validated-form') + const validatableFormSectionComponents = [] - const setDate = new Date(thisDatePickerRangeAsJQuery.val()) + validatedFormCollection.find('.component-date-picker-range').each(function () { + try { + validatableFormSectionComponents.push(new RangedDatePicker($(this), pageNotifier)) + } catch (e) { + console.error('Failed to instantiate ranged date picker with the following jQuery object:') + console.error($(this)) + console.error(e) + } + }) - if (setDate > max && !isNaN(max)) { - valid = false - } else if (setDate < min && !isNaN(min)) { - valid = false - } - }) + validatedFormCollection.on('submit', function (e) { + e.preventDefault() - if (!valid) { - e.preventDefault() + for (const component of validatableFormSectionComponents) { + component.validate() } }) }) diff --git a/app/views/case_contacts/_form.html.erb b/app/views/case_contacts/_form.html.erb index d4ad384247..921885aa0c 100644 --- a/app/views/case_contacts/_form.html.erb +++ b/app/views/case_contacts/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_with(model: case_contact, local: true, id: "casa-contact-form") do |form| %> +<%= form_with(model: case_contact, local: true, id: "casa-contact-form", class: "component-validated-form") do |form| %> <%= render "/shared/error_messages", resource: case_contact %>
@@ -65,14 +65,14 @@
-
<%= form.label :occurred_at, "c. Occurred On" %>
<% occurred_at = @case_contact.occurred_at || Time.zone.now %> <%= form.text_field :occurred_at, value: occurred_at.to_date, - data: {date_format: "yyyy/mm/dd", provide: "datepicker"}, - class: "card-style-1" %> + data: {date_format: "yyyy/mm/dd", provide: "datepicker", max_date: "today"}, + class: "card-style-1 component-date-picker-range", + "component-name": "occurred at" %>
From 62ab7be6ffc459142f36b27c367b8a536305ecbc Mon Sep 17 00:00:00 2001 From: firelemons Date: Sun, 15 Oct 2023 18:23:02 -0500 Subject: [PATCH 04/49] moved component erb to folder, separated date range component from form --- app/views/case_contacts/_form.html.erb | 8 +++----- app/views/layouts/application.html.erb | 2 +- .../{_notifier.erb => components/_notifier.html.erb} | 0 app/views/layouts/components/_ranged_date_picker.html.erb | 5 +++++ 4 files changed, 9 insertions(+), 6 deletions(-) rename app/views/layouts/{_notifier.erb => components/_notifier.html.erb} (100%) create mode 100644 app/views/layouts/components/_ranged_date_picker.html.erb diff --git a/app/views/case_contacts/_form.html.erb b/app/views/case_contacts/_form.html.erb index 921885aa0c..577dff6787 100644 --- a/app/views/case_contacts/_form.html.erb +++ b/app/views/case_contacts/_form.html.erb @@ -68,11 +68,9 @@
<%= form.label :occurred_at, "c. Occurred On" %>
<% occurred_at = @case_contact.occurred_at || Time.zone.now %> - <%= form.text_field :occurred_at, - value: occurred_at.to_date, - data: {date_format: "yyyy/mm/dd", provide: "datepicker", max_date: "today"}, - class: "card-style-1 component-date-picker-range", - "component-name": "occurred at" %> + <%= render "layouts/components/ranged_date_picker", + form: form, model_field: :occurred_at, initial_value: occurred_at.to_date, + max_date: "today", component_name: "occurred at" %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 52f72cf642..c4f65a810e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -62,7 +62,7 @@ - <%= render "layouts/notifier" %> + <%= render "layouts/components/notifier" %>