diff --git a/app/javascript/controllers/money_field_controller.js b/app/javascript/controllers/money_field_controller.js index 686ca713a..db8b1211b 100644 --- a/app/javascript/controllers/money_field_controller.js +++ b/app/javascript/controllers/money_field_controller.js @@ -1,11 +1,17 @@ import { Controller } from "@hotwired/stimulus"; -import parseLocaleFloat from "utils/parse_locale_float"; import { CurrenciesService } from "services/currencies_service"; +import parseLocaleFloat from "utils/parse_locale_float"; // Connects to data-controller="money-field" // when currency select change, update the input value with the correct placeholder and step export default class extends Controller { static targets = ["amount", "currency", "symbol"]; + static values = { + precision: Number, + step: String, + }; + + requestSequence = 0; handleCurrencyChange(e) { const selectedCurrency = e.target.value; @@ -13,18 +19,33 @@ export default class extends Controller { } updateAmount(currency) { - new CurrenciesService().get(currency).then((currency) => { - this.amountTarget.step = currency.step; + const requestId = ++this.requestSequence; + new CurrenciesService().get(currency).then((currencyData) => { + if (requestId !== this.requestSequence) return; + + this.amountTarget.step = + this.hasStepValue && + this.stepValue !== "" && + (this.stepValue === "any" || Number.isFinite(Number(this.stepValue))) + ? this.stepValue + : currencyData.step; const rawValue = this.amountTarget.value.trim(); if (rawValue !== "") { const parsedAmount = parseLocaleFloat(rawValue); if (Number.isFinite(parsedAmount)) { - this.amountTarget.value = parsedAmount.toFixed(currency.default_precision); + const precision = + this.hasPrecisionValue && Number.isInteger(this.precisionValue) + ? this.precisionValue + : currencyData.default_precision; + this.amountTarget.value = parsedAmount.toFixed(precision); } } - this.symbolTarget.innerText = currency.symbol; + this.symbolTarget.innerText = currencyData.symbol; + }).catch(() => { + // Catch prevents Unhandled Promise Rejection for network failures. + // Silently ignored as they are unactionable by the user. }); } } diff --git a/app/views/shared/_money_field.html.erb b/app/views/shared/_money_field.html.erb index 787798c44..41776c28f 100644 --- a/app/views/shared/_money_field.html.erb +++ b/app/views/shared/_money_field.html.erb @@ -7,7 +7,10 @@ end currency = Money::Currency.new(currency_value || options[:default_currency] || "USD") %> -