mirror of
https://github.com/we-promise/sure.git
synced 2026-04-12 08:37:22 +00:00
* fix: allow high precision for security prices in trade forms (to solve #1323) * fix: prevent race conditions on currency selection in money field * fix: silently ignore currency fetch errors in money field
This commit is contained in:
@@ -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.
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
end
|
||||
currency = Money::Currency.new(currency_value || options[:default_currency] || "USD") %>
|
||||
|
||||
<div class="form-field <%= options[:container_class] %>" data-controller="money-field">
|
||||
<div class="form-field <%= options[:container_class] %>"
|
||||
data-controller="money-field"
|
||||
<% if options[:precision].present? %>data-money-field-precision-value="<%= options[:precision] %>"<% end %>
|
||||
<% if options[:step].present? %>data-money-field-step-value="<%= options[:step] %>"<% end %>>
|
||||
<% if options[:label_tooltip] %>
|
||||
<div class="form-field__header">
|
||||
<%= form.label options[:label] || t(".label"), class: "form-field__label" do %>
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
<div class="space-y-1">
|
||||
<%= f.label :price, t(".price_label"), class: "font-medium text-sm text-primary block" %>
|
||||
<%= f.number_field :price,
|
||||
step: "0.0001",
|
||||
step: "any",
|
||||
min: "0",
|
||||
placeholder: t(".price_placeholder"),
|
||||
class: "form-field__input border border-secondary rounded-lg px-3 py-2 w-full text-primary bg-container",
|
||||
|
||||
Reference in New Issue
Block a user