fix: quantity/price fields padded with zeros when editing a transaction

The API returns quantity and price_per_unit at their full Numeric(38,18)
scale (e.g. "3.000000000000000000") since crypto quantities need up to 18
decimal places for wei-level amounts — correct for computation, but the
edit form pre-filled these raw strings straight into the inputs.

Added trimTrailingZeros() to lib/format.ts and used it when pre-filling
CryptoTransactionModal in edit mode. Trims the string directly rather than
round-tripping through Number(), which would risk rounding a genuine
18-decimal-place amount through floating point instead of just stripping
padding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01855PiW5Wd8n4aRW4n9kByY
This commit is contained in:
ZProger
2026-08-30 05:10:29 +03:00
parent 2ad39f9780
commit 7deacd2a98
2 changed files with 20 additions and 2 deletions

View File

@@ -4,6 +4,7 @@ import { Button } from "@/components/ui/Button";
import { Dialog } from "@/components/ui/Dialog";
import { Input, Label } from "@/components/ui/Input";
import { useAddCryptoTransaction, useUpdateCryptoTransaction } from "@/hooks/useCrypto";
import { trimTrailingZeros } from "@/lib/format";
import { useTranslation } from "@/lib/i18n";
import { cn } from "@/lib/utils";
import type { CryptoHolding, CryptoTransaction, CryptoTransactionType } from "@/types";
@@ -39,8 +40,11 @@ export function CryptoTransactionModal({ open, onClose, holding, transaction = n
if (!open) return;
if (transaction) {
setType(transaction.type);
setQuantity(transaction.quantity);
setPricePerUnit(transaction.price_per_unit);
// The API returns these at full Numeric(38,18) scale (e.g.
// "3.000000000000000000") — trimmed here so the field shows what was
// actually entered, not a wall of padding zeros.
setQuantity(trimTrailingZeros(transaction.quantity));
setPricePerUnit(trimTrailingZeros(transaction.price_per_unit));
setDate(transaction.date);
setNote(transaction.note ?? "");
} else {

View File

@@ -32,6 +32,20 @@ export function maskAmount(formatted: string, hidden: boolean): string {
return hidden ? "••••" : formatted;
}
/** Strips trailing zeros from a decimal string for pre-filling an editable
* number input — the backend stores crypto quantity/price as Numeric(38,18)
* and returns it at full scale (e.g. "3.000000000000000000"), which is
* correct for computation but not something anyone wants to see or edit
* around in a form field. Works on the string directly rather than via
* Number(), which would round a genuine 18-decimal-place amount (a
* wei-level token quantity) through floating point instead of just
* trimming the padding. */
export function trimTrailingZeros(value: string): string {
if (!value.includes(".")) return value;
const trimmed = value.replace(/0+$/, "").replace(/\.$/, "");
return trimmed === "" || trimmed === "-" ? "0" : trimmed;
}
const MONTH_LABELS_EN = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] as const;
const MONTH_LABELS_RU = ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"] as const;