Skip to content

Commit d31c249

Browse files
committed
feat: formatting of the PNK balance, stake and amount in input field
1 parent 167d342 commit d31c249

File tree

8 files changed

+105
-24
lines changed

8 files changed

+105
-24
lines changed

cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"repartitions",
3535
"solhint",
3636
"typechain",
37+
"uncommify",
3738
"Unslashed",
3839
"viem",
3940
"wagmi"
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React, { useState } from "react";
2+
import styled from "styled-components";
3+
import { Field } from "@kleros/ui-components-library";
4+
5+
const Container = styled.div`
6+
width: 100%;
7+
height: fit-content;
8+
`;
9+
10+
const StyledField = styled(Field)`
11+
width: 100%;
12+
height: fit-content;
13+
`;
14+
15+
interface INumberInputField {
16+
placeholder?: string;
17+
message?: string;
18+
value?: string;
19+
onChange?: (value: string) => void;
20+
formatter?: (value: string) => string;
21+
}
22+
23+
export const NumberInputField: React.FunctionComponent<INumberInputField> = ({
24+
placeholder,
25+
message,
26+
value,
27+
onChange,
28+
formatter,
29+
}) => {
30+
const [isEditing, setIsEditing] = useState(false);
31+
32+
const toggleEditing = () => {
33+
setIsEditing(!isEditing);
34+
};
35+
36+
return (
37+
<Container>
38+
{isEditing ? (
39+
<StyledField
40+
type="number"
41+
value={value}
42+
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
43+
onChange && onChange(event.target.value);
44+
}}
45+
placeholder={placeholder}
46+
message={message}
47+
variant="info"
48+
onBlur={toggleEditing}
49+
/>
50+
) : (
51+
<StyledField
52+
type="text"
53+
value={formatter ? formatter(value ?? "0") : value}
54+
placeholder={placeholder}
55+
message={message}
56+
variant="info"
57+
onFocus={toggleEditing}
58+
readOnly
59+
/>
60+
)}
61+
</Container>
62+
);
63+
};

web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ import { useParams } from "react-router-dom";
44
import { formatEther } from "viem";
55
import { useDebounce } from "react-use";
66
import { useAccount } from "wagmi";
7-
import { Field } from "@kleros/ui-components-library";
7+
import { NumberInputField } from "components/NumberInputField";
88
import { useParsedAmount } from "hooks/useParsedAmount";
99
import { useCourtDetails } from "hooks/queries/useCourtDetails";
1010
import { useKlerosCoreGetJurorBalance, usePnkBalanceOf } from "hooks/contracts/generated";
1111
import StakeWithdrawButton, { ActionType } from "./StakeWithdrawButton";
12+
import { formatPNK, roundNumberDown } from "utils/format";
1213
import { isUndefined } from "utils/index";
14+
import { commify, uncommify } from "utils/commify";
1315
import { EnsureChain } from "components/EnsureChain";
1416

15-
const StyledField = styled(Field)`
17+
const StyledField = styled(NumberInputField)`
1618
width: 100%;
1719
height: fit-content;
1820
`;
@@ -53,7 +55,7 @@ const InputDisplay: React.FC<IInputDisplay> = ({
5355
}) => {
5456
const [debouncedAmount, setDebouncedAmount] = useState("");
5557
useDebounce(() => setDebouncedAmount(amount), 500, [amount]);
56-
const parsedAmount = useParsedAmount(debouncedAmount);
58+
const parsedAmount = useParsedAmount(uncommify(debouncedAmount));
5759

5860
const { id } = useParams();
5961
const { data: courtDetails } = useCourtDetails(id);
@@ -63,13 +65,13 @@ const InputDisplay: React.FC<IInputDisplay> = ({
6365
args: [address ?? "0x"],
6466
watch: true,
6567
});
66-
const parsedBalance = formatEther(balance ?? 0n);
68+
const parsedBalance = formatPNK(balance ?? 0n, 0, true);
6769
const { data: jurorBalance } = useKlerosCoreGetJurorBalance({
6870
enabled: !isUndefined(address),
6971
args: [address, id],
7072
watch: true,
7173
});
72-
const parsedStake = formatEther(jurorBalance?.[0] || 0n);
74+
const parsedStake = formatPNK(jurorBalance?.[0] || 0n, 0, true);
7375
const isStaking = action === ActionType.stake;
7476

7577
return (
@@ -87,10 +89,9 @@ const InputDisplay: React.FC<IInputDisplay> = ({
8789
</LabelArea>
8890
<InputArea>
8991
<StyledField
90-
type="number"
91-
value={amount}
92+
value={uncommify(amount)}
9293
onChange={(e) => {
93-
setAmount(e.target.value);
94+
setAmount(e);
9495
}}
9596
placeholder={isStaking ? "Amount to stake" : "Amount to withdraw"}
9697
message={
@@ -101,7 +102,7 @@ const InputDisplay: React.FC<IInputDisplay> = ({
101102
courtDetails?.court.minStake ?? 0n
102103
)} PNK.`
103104
}
104-
variant="info"
105+
formatter={(number: string) => commify(roundNumberDown(Number(number)))}
105106
/>
106107
<EnsureChain>
107108
<StakeWithdrawButton

web/src/pages/Courts/CourtDetails/Stats.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import styled from "styled-components";
33
import { useParams } from "react-router-dom";
44
import { useCourtDetails, CourtDetailsQuery } from "queries/useCourtDetails";
55
import { useCoinPrice } from "hooks/useCoinPrice";
6-
import { formatETH, formatPNK, formatUnitsWei, formatUSD, isUndefined } from "utils/index";
6+
import { formatETH, formatPNK, formatUnitsWei, formatUSD } from "utils/format";
7+
import { isUndefined } from "utils/index";
78
import { calculateSubtextRender } from "utils/calculateSubtextRender";
89
import { CoinIds } from "consts/coingecko";
910
import StatDisplay, { IStatDisplay } from "components/StatDisplay";

web/src/pages/Home/CourtOverview/Stats.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import EthereumIcon from "svgs/icons/ethereum.svg";
88
import PNKRedistributedIcon from "svgs/icons/redistributed-pnk.svg";
99
import JurorIcon from "svgs/icons/user.svg";
1010
import BalanceIcon from "svgs/icons/law-balance.svg";
11-
import { formatETH, formatPNK, formatUnitsWei, formatUSD, isUndefined } from "utils/index";
11+
import { formatETH, formatPNK, formatUnitsWei, formatUSD } from "utils/format";
12+
import { isUndefined } from "utils/index";
1213
import { calculateSubtextRender } from "utils/calculateSubtextRender";
1314
import { CoinIds } from "consts/coingecko";
1415
import { useHomePageContext, HomePageQuery, HomePageQueryDataPoints } from "hooks/useHomePageContext";

web/src/utils/commify.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,7 @@ export function commify(value: string | number): string {
5252

5353
return negative + formatted.join(",") + suffix;
5454
}
55+
56+
export function uncommify(value: string): string {
57+
return value.replace(/,/g, "");
58+
}

web/src/utils/format.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { formatEther, formatUnits } from "viem";
2+
import { commify } from "./commify";
3+
4+
export const roundNumberDown = (value: number, fractionDigits = 0) => {
5+
const factor = 10 ** fractionDigits;
6+
return Math.floor(value * factor) / factor;
7+
};
8+
9+
export const formatUnitsWei = (value: bigint) => formatUnits(value, 18);
10+
11+
export const formatValue = (value: string, fractionDigits, roundDown) => {
12+
let units = Number(value);
13+
if (roundDown) units = roundNumberDown(units, fractionDigits);
14+
return commify(units.toFixed(fractionDigits));
15+
};
16+
17+
export const formatPNK = (value: bigint, fractionDigits = 0, roundDown = false) =>
18+
formatValue(formatUnitsWei(value), fractionDigits, roundDown);
19+
20+
export const formatETH = (value: bigint, fractionDigits = 4, roundDown = false) =>
21+
formatValue(formatEther(value), fractionDigits, roundDown);
22+
23+
export const formatUSD = (value: number, fractionDigits = 2) => "$" + commify(Number(value).toFixed(fractionDigits));

web/src/utils/index.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1 @@
1-
import { formatEther, formatUnits } from "viem";
2-
import { commify } from "./commify";
3-
41
export const isUndefined = (maybeObject: any): maybeObject is undefined => typeof maybeObject === "undefined";
5-
6-
export const formatUnitsWei = (value: bigint) => formatUnits(value, 18);
7-
8-
export const formatPNK = (value: bigint, fractionDigits = 0) =>
9-
commify(Number(formatUnitsWei(value)).toFixed(fractionDigits));
10-
11-
export const formatETH = (value: bigint, fractionDigits = 4) =>
12-
commify(Number(formatEther(value)).toFixed(fractionDigits));
13-
14-
export const formatUSD = (value: number, fractionDigits = 2) => "$" + commify(Number(value).toFixed(fractionDigits));

0 commit comments

Comments
 (0)