Skip to content

Commit

Permalink
Feat/nexui amount input (#799)
Browse files Browse the repository at this point in the history
* feat(home): use nextui input and checkbox

* fix(home): amount-input value

* feat(components): use nextui input

* feat(components): use nextui input for amount

* chore: cleanup

* test(components): use valid props and adjust tests

* chore: cleanup
  • Loading branch information
escapedcat authored Dec 5, 2024
1 parent 812cd32 commit e85ac08
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 40 deletions.
54 changes: 27 additions & 27 deletions src/components/AmountInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AppContext, Unit } from "@/context/app-context";
import { convertBtcToSat, convertSatToBtc, formatAmount } from "@/utils/format";
import { ArrowsRightLeftIcon } from "@heroicons/react/24/outline";
import { Input } from "@nextui-org/react";
import { ChangeEvent, FC, useContext, useState } from "react";
import type { FieldError, UseFormRegisterReturn } from "react-hook-form";
import { useTranslation } from "react-i18next";
Expand Down Expand Up @@ -61,35 +62,34 @@ const AmountInput: FC<Props> = ({
};

return (
<>
<label className="label-underline" htmlFor={register.name}>
{t("wallet.amount")}
</label>
<div className="flex">
<input
{...register}
id={register.name}
className={`${errorMessage ? "input-error" : "input-underline"}`}
type="text"
value={amountInput}
onChange={onChangeHandler}
disabled={disabled}
/>
<span
className="ml-6 flex w-4/12 items-center justify-center rounded bg-gray-600 p-1 shadow-md"
<Input
{...register}
label={t("wallet.amount")}
id={register.name}
type="text"
classNames={{
inputWrapper:
"bg-tertiary group-data-[focus=true]:bg-tertiary group-data-[hover=true]:bg-tertiary",
}}
value={amountInput}
onChange={onChangeHandler}
isDisabled={disabled}
isInvalid={!!errorMessage}
errorMessage={errorMessage?.message}
endContent={
<button
className="focus:outline-none"
type="button"
onClick={toggleHandler}
aria-label="toggle password visibility"
>
{unit}
<ArrowsRightLeftIcon className="ml-1 h-5 w-5 text-white" />
</span>
</div>

<p
className={`text-left text-sm text-red-500 ${errorMessage ? "" : "invisible"}`}
>
{errorMessage?.message || "error"}
</p>
</>
<span className="whitespace-nowrap text-small text-default-400">
{unit}
<ArrowsRightLeftIcon className="ml-1 inline-block h-5 w-5" />
</span>
</button>
}
/>
);
};

Expand Down
12 changes: 7 additions & 5 deletions src/pages/Home/SendModal/SendOnChain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ConfirmModal } from "@/components/ConfirmModal";
import { stringToNumber } from "@/utils/format";
import { Checkbox } from "@nextui-org/checkbox";
import { Input } from "@nextui-org/react";
import { ChangeEvent, FC, useState } from "react";
import { ChangeEvent, type FC, useState } from "react";
import type { SubmitHandler } from "react-hook-form";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
Expand All @@ -30,6 +30,9 @@ export interface SendOnChainForm {

const SendOnChain: FC<Props> = ({ balance, onConfirm, confirmData }) => {
const { t } = useTranslation();
const [updated, setUpdated] = useState(false);
const [amount, setAmount] = useState(0);

const {
register,
handleSubmit,
Expand All @@ -39,8 +42,6 @@ const SendOnChain: FC<Props> = ({ balance, onConfirm, confirmData }) => {
} = useForm<SendOnChainForm>({
mode: "onChange",
});
const [updated, setUpdated] = useState(false);
const [amount, setAmount] = useState(0);

if (!updated && confirmData?.invoiceType === TxType.ONCHAIN) {
setUpdated(true);
Expand All @@ -54,9 +55,11 @@ const SendOnChain: FC<Props> = ({ balance, onConfirm, confirmData }) => {
}

const spendAll = watch("spendAll", false);

const onSubmit: SubmitHandler<SendOnChainForm> = (data) =>
// overwrite amount to submit number instead of string
onConfirm({ ...data, invoiceType: TxType.ONCHAIN, amount });

const changeAmountHandler = (event: ChangeEvent<HTMLInputElement>) => {
setAmount(+event.target.value);
};
Expand All @@ -69,7 +72,6 @@ const SendOnChain: FC<Props> = ({ balance, onConfirm, confirmData }) => {
<fieldset className="flex flex-col items-center justify-center text-center">
<div className="w-full py-1">
<Input
className="w-full"
classNames={{
inputWrapper:
"bg-tertiary group-data-[focus=true]:bg-tertiary group-data-[hover=true]:bg-tertiary",
Expand Down Expand Up @@ -102,7 +104,7 @@ const SendOnChain: FC<Props> = ({ balance, onConfirm, confirmData }) => {
},
validate: {
greaterThanZero: (val) =>
//@ts-ignore
// @ts-expect-error is will be returned as formatted string and needs to be converted to number
stringToNumber(val) > 0 ||
t("forms.validation.chainAmount.required"),
},
Expand Down
13 changes: 9 additions & 4 deletions src/pages/Home/SendModal/__tests__/ConfirmSend.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ describe("ConfirmSend", () => {
await user.type(amountInput, "999");

amountInput = await screen.findByLabelText("wallet.amount");
screen.debug(amountInput);

await waitFor(() => expect(amountInput).toHaveClass("input-error"));
await waitFor(() => expect(amountInput).toHaveAttribute("aria-invalid"));

expect(
await screen.findByText("forms.validation.chainAmount.max"),
Expand All @@ -75,7 +76,7 @@ describe("ConfirmSend", () => {

amountInput = await screen.findByLabelText("wallet.amount");

await waitFor(() => expect(amountInput).toHaveClass("input-error"));
await waitFor(() => expect(amountInput).toHaveAttribute("aria-invalid"));

expect(
screen.getByText("forms.validation.chainAmount.required"),
Expand All @@ -91,7 +92,9 @@ describe("ConfirmSend", () => {
) as HTMLInputElement;

await user.type(amountInput, "100");
await waitFor(() => expect(amountInput).not.toHaveClass("input-error"));
await waitFor(() =>
expect(amountInput).not.toHaveAttribute("aria-invalid"),
);

expect(
screen.getByRole("button", { name: "settings.confirm" }),
Expand All @@ -117,7 +120,9 @@ describe("ConfirmSend", () => {
) as HTMLInputElement;

await user.type(amountInput, "10");
await waitFor(() => expect(amountInput).not.toHaveClass("input-error"));
await waitFor(() =>
expect(amountInput).not.toHaveAttribute("aria-invalid"),
);

const confirmBtn = screen.getByRole("button", {
name: "settings.confirm",
Expand Down
10 changes: 6 additions & 4 deletions src/pages/Home/SendModal/__tests__/SendModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { render, screen, mockedDisclosure } from "test-utils";

const basicProps: Props = {
lnBalance: 0,
onchainBalance: 0,
onchainBalance: 21,
disclosure: mockedDisclosure,
};

Expand Down Expand Up @@ -131,9 +131,10 @@ describe("SendModal", () => {
});

it("test a valid form pass", async () => {
const addressInput = await screen.findByLabelText("wallet.address");
const amountInput = await screen.findByLabelText("wallet.amount");
const feeInput = await screen.findByLabelText("tx.fee");
const addressInput = screen.getByLabelText("wallet.address");
const amountInput = screen.getByLabelText("wallet.amount");
const feeInput = screen.getByLabelText("tx.fee");

await user.type(addressInput, "bc1q12345");
await user.type(amountInput, "20123");
await user.type(feeInput, "200");
Expand All @@ -144,6 +145,7 @@ describe("SendModal", () => {

expect(confirmBtn).toBeEnabled();
await user.click(confirmBtn);

// Should display confirm modal with amount
expect(await screen.findByText("20,123 Sat")).toBeInTheDocument();
});
Expand Down

0 comments on commit e85ac08

Please sign in to comment.