Skip to content

Commit

Permalink
Enforce en-US locale for numbers formatting (#767)
Browse files Browse the repository at this point in the history
* Enforce en-US locale for numbers formatting

* Coding style

* Name types
bpierre authored Jan 27, 2025
1 parent c799889 commit 7c93e11
Showing 9 changed files with 43 additions and 29 deletions.
4 changes: 2 additions & 2 deletions frontend/app/src/comps/LeverageField/LeverageField.tsx
Original file line number Diff line number Diff line change
@@ -90,7 +90,7 @@ export function LeverageField({
fontVariantNumeric: "tabular-nums",
})}
>
{dn.format(debt, { digits: 2, trailingZeros: true })}
{fmtnum(debt)}
</span>
{" BOLD"}
</>
@@ -229,7 +229,7 @@ export function useLeverageField({
}, [maxLeverageFactor]);

const liquidationPriceField = useInputFieldValue(
(value) => `$ ${dn.format(value, { digits: 2, trailingZeros: true })}`,
(value) => `$ ${fmtnum(value)}`,
{
onChange: ({ parsed: liquidationPrice, focused }) => {
if (liquidationPrice && dn.gt(liquidationPrice, 0) && liquidationPriceField.isFocused && focused) {
6 changes: 3 additions & 3 deletions frontend/app/src/comps/Positions/PositionCardBorrow.tsx
Original file line number Diff line number Diff line change
@@ -103,7 +103,7 @@ export function PositionCardBorrow({
alignItems: "cente",
})}
>
Backed by {deposit ? dn.format(deposit, 2) : "−"} {token.name}
Backed by {deposit ? fmtnum(deposit, 2) : "−"} {token.name}
<TokenIcon size="small" symbol={token.symbol} />
</div>
),
@@ -141,7 +141,7 @@ export function PositionCardBorrow({
: "var(--status-negative)",
}}
>
{dn.format(dn.mul(ltv, 100), 2)}%
{fmtnum(ltv, 2, 100)}%
</div>
)}
</div>
@@ -191,7 +191,7 @@ export function PositionCardBorrow({
color: "positionContent",
})}
>
{dn.format(dn.mul(interestRate, 100), 2)}%
{fmtnum(interestRate, 2, 100)}%
</div>
{batchManager && (
<div
7 changes: 4 additions & 3 deletions frontend/app/src/comps/Positions/PositionCardLeverage.tsx
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import type { PositionLoanCommitted } from "@/src/types";
import type { ReactNode } from "react";

import { formatRedemptionRisk } from "@/src/formatting";
import { fmtnum } from "@/src/formatting";
import { getLiquidationRisk, getLtv, getRedemptionRisk } from "@/src/liquity-math";
import { getCollToken } from "@/src/liquity-utils";
import { usePrice } from "@/src/services/Prices";
@@ -78,7 +79,7 @@ export function PositionCardLeverage({
main={{
value: (
<HFlex gap={8} alignItems="center" justifyContent="flex-start">
{deposit ? dn.format(deposit, 2) : "−"}
{deposit ? fmtnum(deposit, 2) : "−"}
<TokenIcon size={24} symbol={token.symbol} />
</HFlex>
),
@@ -117,7 +118,7 @@ export function PositionCardLeverage({
: "var(--status-negative)",
}}
>
{dn.format(dn.mul(ltv, 100), 2)}%
{fmtnum(ltv, 2, 100)}%
</div>
)}
</div>
@@ -169,7 +170,7 @@ export function PositionCardLeverage({
color: "positionContent",
})}
>
{dn.format(dn.mul(interestRate, 100), 2)}%
{fmtnum(interestRate, 2, 100)}%
</div>
</div>
}
Original file line number Diff line number Diff line change
@@ -84,9 +84,8 @@ export function StakePositionSummary({
// pctShare(t) = userVotingPower(t) / totalVotingPower(t)
const share = dn.div([userVpLive, 18], [totalVpLive, 18]);

const sharePct = dn.mul(share, 100);
const sharePctFormatted = dn.format(sharePct, { digits: 12, trailingZeros: true }) + "%";
const sharePctRoundedFormatted = fmtnum(sharePct, { digits: 2, trailingZeros: true }) + "%";
const sharePctFormatted = fmtnum(share, "12z", 100) + "%";
const sharePctRoundedFormatted = fmtnum(share, "2z", 100) + "%";

votingPowerRef.current.innerHTML = sharePctRoundedFormatted;
votingPowerRef.current.title = sharePctFormatted;
@@ -371,7 +370,7 @@ export function StakePositionSummary({
<p>
Voting power increases over time based on the total amount of LQTY staked.
</p>
{account.address && (
{account.address && (govUser.data?.stakedLQTY ?? 0n) > 0n && (
<div
className={css({
display: "flex",
33 changes: 23 additions & 10 deletions frontend/app/src/formatting.ts
Original file line number Diff line number Diff line change
@@ -4,25 +4,29 @@ import { DNUM_0, DNUM_1 } from "@/src/dnum-utils";
import * as dn from "dnum";
import { match, P } from "ts-pattern";

// Dnum formatting options
const dnFormatOptions = {
// dnum formatting presets
const dnFormatPresets = {
"1z": { digits: 1, trailingZeros: true },
"2z": { digits: 2, trailingZeros: true },
"12z": { digits: 12, trailingZeros: true },
"2diff": { digits: 2, signDisplay: "exceptZero" },
"4diff": { digits: 4, signDisplay: "exceptZero" },
"compact": { compact: true, digits: 2 },
"full": undefined, // dnum defaults
} as const;

function isDnFormatName(value: unknown): value is keyof typeof dnFormatOptions {
return typeof value === "string" && value in dnFormatOptions;
type DnFormatPresetName = keyof typeof dnFormatPresets;
type DnumFormatOptions = number | Parameters<typeof dn.format>[1];

function isDnFormatPresetName(value: unknown): value is DnFormatPresetName {
return typeof value === "string" && value in dnFormatPresets;
}

export function fmtnum(
value: Dnum | number | null | undefined,
optionsOrFormatName:
| keyof typeof dnFormatOptions
| Parameters<typeof dn.format>[1] = "2z",
| DnFormatPresetName
| DnumFormatOptions = "2z",
scale = 1, // pass 100 here to format as percentage
) {
if (value === null || value === undefined) {
@@ -35,11 +39,20 @@ export function fmtnum(
value = dn.mul(value, scale);
}

const options: Exclude<Parameters<typeof dn.format>[1], number> = isDnFormatName(optionsOrFormatName)
? dnFormatOptions[optionsOrFormatName]
: optionsOrFormatName;
let options: DnumFormatOptions = (
isDnFormatPresetName(optionsOrFormatName)
? dnFormatPresets[optionsOrFormatName]
: optionsOrFormatName
) ?? {};

if (typeof options === "number") {
options = { digits: options };
}

const formatted = dn.format(value, options);
const formatted = dn.format(value, {
...options,
locale: "en-US",
});

// replace values rounded to 0.0…0 with 0.0…1 so they don't look like 0
if (typeof options?.digits === "number" && options.digits > 0 && value[0] > 0n) {
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ export function PanelUpdateBorrowPosition({

// deposit change
const [depositMode, setDepositMode] = useState<ValueUpdateMode>("add");
const depositChange = useInputFieldValue((value) => dn.format(value));
const depositChange = useInputFieldValue((value) => fmtnum(value, "full"));

// deposit update
const newDeposit = depositChange.parsed && (
@@ -72,7 +72,7 @@ export function PanelUpdateBorrowPosition({

// debt change
const [debtMode, setDebtMode] = useState<ValueUpdateMode>("add");
const debtChange = useInputFieldValue((value) => dn.format(value));
const debtChange = useInputFieldValue((value) => fmtnum(value, "full"));

const newDebt = debtChange.parsed && (
debtMode === "remove"
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ export function PanelUpdateLeveragePosition({

// deposit change
const [depositMode, setDepositMode] = useState<"add" | "remove">("add");
const depositChange = useInputFieldValue((value) => dn.format(value));
const depositChange = useInputFieldValue((value) => fmtnum(value, "full"));
const [userLeverageFactor, setUserLeverageFactor] = useState(
initialLoanDetails.leverageFactor ?? 1,
);
5 changes: 3 additions & 2 deletions frontend/app/src/screens/LoanScreen/PanelUpdateRate.tsx
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import { InterestRateField } from "@/src/comps/InterestRateField/InterestRateFie
import { UpdateBox } from "@/src/comps/UpdateBox/UpdateBox";
import content from "@/src/content";
import { useInputFieldValue } from "@/src/form-utils";
import { fmtnum } from "@/src/formatting";
import { formatRisk } from "@/src/formatting";
import { getLoanDetails } from "@/src/liquity-math";
import { getCollToken } from "@/src/liquity-utils";
@@ -38,10 +39,10 @@ export function PanelUpdateRate({

const collPrice = usePrice(collToken.symbol);

const deposit = useInputFieldValue((value) => `${dn.format(value)} ${collToken.symbol}`, {
const deposit = useInputFieldValue((value) => `${fmtnum(value, "full")} ${collToken.symbol}`, {
defaultValue: dn.toString(loan.deposit),
});
const debt = useInputFieldValue((value) => `${dn.format(value)} BOLD`, {
const debt = useInputFieldValue((value) => `${fmtnum(value, "full")} BOLD`, {
defaultValue: dn.toString(loan.borrowed),
});

4 changes: 2 additions & 2 deletions frontend/app/src/screens/StakeScreen/PanelStaking.tsx
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ export function PanelStaking() {

const value_ = (focused || !parsedValue || dn.lte(parsedValue, 0))
? value
: `${dn.format(parsedValue)}`;
: `${fmtnum(parsedValue, "full")}`;

const depositDifference = dn.mul(
parsedValue ?? dn.from(0, 18),
@@ -125,7 +125,7 @@ export function PanelStaking() {
value={value_}
placeholder="0.00"
secondary={{
start: parsedValue && lqtyPrice.data ? `$${dn.format(dn.mul(parsedValue, lqtyPrice.data), 2)}` : null,
start: parsedValue && lqtyPrice.data ? `$${fmtnum(dn.mul(parsedValue, lqtyPrice.data), 2)}` : null,
end: mode === "deposit"
? (
lqtyBalance.data && dn.gt(lqtyBalance.data, 0) && (

0 comments on commit 7c93e11

Please sign in to comment.