Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion app/assets/javascripts/application_legacy.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
//= require_self
//= require big
//= require units-converter
//= require validation-utils
//= require migrate-units-form
//= require article-form
//= require unit-conversion-field
Expand Down
87 changes: 19 additions & 68 deletions app/assets/javascripts/group-order-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,14 @@ class GroupOrderForm {
this.groupBalance = config.groupBalance;
this.minimumBalance = config.minimumBalance;

ValidationUtils.setupCustomValidation(this.form$);

this.initializeIncreaseDecreaseButtons();
this.submitButton$.removeAttr('disabled');
this.initializeFormValidation();
}

initializeIncreaseDecreaseButtons() {
this.articleRows$.each((_, element) => this.initializeOrderArticleRow($(element)));
}

initializeFormValidation() {
this.form$.on('submit', (e) => {
// Update all validation messages first
this.articleRows$.each((_, row) => {
const row$ = $(row);
this.updateValidationMessages(row$);
});

// Check if form is valid - browser will prevent submission if invalid
if (!this.form$[0].checkValidity()) {
e.preventDefault();

// Show error messages for all invalid inputs
this.form$.find(':invalid').each((_, invalidInput) => {
const input$ = $(invalidInput);
if (input$.hasClass('goa-quantity')) {
// Trigger validation to show error message
ValidationUtils.validateNumericInput(input$);
}
});

// Focus on first invalid input
const firstInvalid = this.form$.find(':invalid').first();
if (firstInvalid.length > 0) {
firstInvalid.focus();
}
}
});
}

initializeOrderArticleRow(row$) {
const quantity$ = row$.find('.goa-quantity');
const tolerance$ = row$.find('.goa-tolerance');
Expand All @@ -67,20 +34,29 @@ class GroupOrderForm {
row$.find('.btn-ordering.increase').click((event) => this.increaseOrDecrease($(event.target).parents('.btn-group').find('input.numeric'), true));

quantityAndTolerance$.change(() => {
this.updateValidationErrors(quantity$);
this.updateMissingUnits(row$, quantity$);
this.updateBalance();
this.updateValidationMessages(row$);
});
quantityAndTolerance$.keyup(() => quantity$.trigger('change'));
}

// Handle validation events for quantity field only
quantity$.on('invalid', (e) => {
e.preventDefault();
e.stopPropagation();
this.updateValidationMessages(row$);
});
updateValidationErrors(valueField$) {
const errorContainer$ = valueField$
// TODO: This parent().parent() is quite arbitrary:
.parent().parent();
errorContainer$.find('.quantity-field-invalid').remove();

this.updateValidationMessages(row$);
if (valueField$.is(':invalid')) {
if (valueField$[0].validity.stepMismatch || valueField$[0].validity.rangeUnderflow) {
const errorSpan$ = $(`<div class="quantity-field-invalid">${I18n.t('errors.step_error', {min: 0, granularity: valueField$.attr('step')})}</div>`);
errorContainer$.append(errorSpan$);
}
if (valueField$[0].validity.rangeOverflow) {
const errorSpan$ = $(`<div class="quantity-field-invalid">${I18n.t('errors.maximum_quantity_error', {max: valueField$.attr('max')})}</div>`);
errorContainer$.append(errorSpan$);
}
}
}

updateBalance() {
Expand All @@ -102,8 +78,8 @@ class GroupOrderForm {
// determine bgcolor and submit button state according to balance
var bgcolor = '';
if (balance < this.minimumBalance) {
bgcolor = '#FF0000';
this.submitButton$.attr('disabled', 'disabled')
bgcolor = '#FF0000';
this.submitButton$.attr('disabled', 'disabled')
} else {
this.submitButton$.removeAttr('disabled')
}
Expand Down Expand Up @@ -269,30 +245,5 @@ class GroupOrderForm {
var remainder = Big(quantity).mod(packSize).toNumber();
return (remainder > 0 && (Big(remainder).add(tolerance).toNumber() >= packSize));
}

updateValidationMessages(row$) {
const quantity$ = row$.find('.goa-quantity');

if (quantity$.length === 0) return;

const inputElement = quantity$[0];

// Clear any existing validation state
inputElement.setCustomValidity('');

// Use ValidationUtils for validation with error spans
ValidationUtils.validateNumericInput(quantity$);

// Special case: item not available (max = 0)
const rawValue = quantity$.val().trim();
const inputValue = parseFloat(rawValue);
const maxValue = parseFloat(quantity$.attr('max'));

if (maxValue === 0 && inputValue > 0) {
const message = I18n.t('errors.item_not_available');
inputElement.setCustomValidity(message);
ValidationUtils.showValidationMessage(quantity$, message);
}
}
}

20 changes: 6 additions & 14 deletions app/assets/javascripts/unit-conversion-field.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,22 +185,14 @@
const unitLabel = this.unitSelectOptions.find(option => option.value === unit).label;
this.conversionResult$.text('= ' + this.getConversionResult() + ' x ' + unitLabel);
this.conversionResult$.parent().find('.numeric-step-error').remove();
if (this.quantityInput$.is(':invalid')) {
this.applyButton$.attr('disabled', 'disabled');

const errorSpan$ = $('<div class="numeric-step-error"></div>');

// Use ValidationUtils for proper custom error messages
const isValid = ValidationUtils.validateNumericInput(this.quantityInput$, {
errorSpan$: errorSpan$
});

if (isValid) {
this.applyButton$.removeAttr('disabled');
const errorSpan$ = $(`<div class="numeric-step-error">${I18n.t('errors.step_error', {min: 0, granularity: this.quantityInput$.attr('step')})}</div>`);
errorSpan$.show();
this.conversionResult$.after(errorSpan$);
} else {
this.applyButton$.attr('disabled', 'disabled');
if (errorSpan$.text()) {
errorSpan$.show();
this.conversionResult$.after(errorSpan$);
}
this.applyButton$.removeAttr('disabled');
}
}

Expand Down
155 changes: 0 additions & 155 deletions app/assets/javascripts/validation-utils.js

This file was deleted.

1 change: 0 additions & 1 deletion app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@
@import "list.missing";
@import "recurring_select";
@import "actiontext";
@import "validation";
10 changes: 2 additions & 8 deletions app/assets/stylesheets/bootstrap_and_overrides.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ tr.order-article {
}

.units_received_cell {


.btn-group .btn-ordering {
margin-top: 0;
Expand Down Expand Up @@ -704,20 +704,14 @@ td.mr-1 > *:last-child {
user-select: none;
}

.numeric-step-error {
display: none;
.quantity-field-invalid {
color: #b94a48;
}

.btn-group.numeric-step > input:invalid {
border: 1px solid #b94a48;
}

.btn-group.numeric-step:has(> input:invalid) + .numeric-step-error {
display: block;
}


.form-group .select2-container {
width: 200px;
}
Expand Down
19 changes: 0 additions & 19 deletions app/assets/stylesheets/validation.scss

This file was deleted.

3 changes: 0 additions & 3 deletions app/views/group_orders/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@
- quantity_data['used_quantity'] = @ordering_data[:order_articles][order_article.id][:used_quantity]
- quantity_data['price'] = @ordering_data[:order_articles][order_article.id][:price]
- quantity_data['minimum_order_quantity'] = @ordering_data[:order_articles][order_article.id][:minimum_order_quantity] unless @ordering_data[:order_articles][order_article.id][:minimum_order_quantity].nil?
- quantity_data['maximum_order_quantity'] = @ordering_data[:order_articles][order_article.id][:maximum_order_quantity] unless @ordering_data[:order_articles][order_article.id][:maximum_order_quantity].nil?
- quantity_data['e2e-order-article-id'] = order_article.id
%td.used-unused
%span.used= number_with_precision(@ordering_data[:order_articles][order_article.id][:used_quantity], precision: 3, strip_insignificant_zeros: true)
Expand All @@ -129,8 +128,6 @@
%a.btn.btn-ordering.increase
%i.glyphicon.glyphicon-plus
%input.goa-quantity{type: "number", name: "group_order[group_order_articles_attributes][#{order_article.id}][quantity]", value: @ordering_data[:order_articles][order_article.id][:quantity], data: quantity_data, autocomplete: 'off', class: 'form-control numeric', style: ('display:none' if @order.stockit?), min: 0, max: (@ordering_data[:order_articles][order_article.id][:quantity_available]), step: order_article.article_version.group_order_granularity}
%span.numeric-step-error{style: 'display: none;'}
= t('errors.step_error', granularity: order_article.article_version.group_order_granularity, min: 0)

%td.used-unused-tolerance{style: ('display:none' if @order.stockit?)}
- if (order_article.article_version.uses_tolerance?)
Expand Down
Loading