Skip to content

Commit

Permalink
56. Fix the logical condition for displaying the warning. (#69)
Browse files Browse the repository at this point in the history
Co-authored-by: nevendiulgerov <[email protected]>
Co-authored-by: brunomenezes <[email protected]>
  • Loading branch information
3 people authored Jan 30, 2024
1 parent b7f5686 commit 37045ff
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 83 deletions.
38 changes: 12 additions & 26 deletions apps/web/src/components/sendTransaction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import {
EtherDepositForm,
RawInputForm,
} from "@cartesi/rollups-explorer-ui";
import { FC, useMemo, useState } from "react";
import { Select } from "@mantine/core";
import { useApplicationsQuery, useTokensQuery } from "../graphql";
import { useDebouncedValue } from "@mantine/hooks";
import { FC, useState } from "react";
import { useSearchApplications } from "../hooks/useSearchApplications";
import { useSearchTokens } from "../hooks/useSearchTokens";

export type DepositType =
| "ether"
Expand All @@ -22,36 +23,20 @@ interface DepositProps {
}

const SendTransaction: FC<DepositProps> = ({
initialDepositType = "ether",
initialDepositType = "erc20",
}) => {
const [depositType, setDepositType] =
useState<DepositType>(initialDepositType);
const [applicationId, setApplicationId] = useState("");
const [applicationId, setApplicationId] = useState<string>("");
const [tokenId, setTokenId] = useState<string>("");
const [debouncedApplicationId] = useDebouncedValue(applicationId, 400);
const [{ data: applicationData, fetching }] = useApplicationsQuery({
variables: {
limit: 10,
where: {
id_containsInsensitive: debouncedApplicationId ?? "",
},
},
const [debouncedTokenId] = useDebouncedValue(tokenId, 400);
const { applications, fetching } = useSearchApplications({
address: debouncedApplicationId,
});
const applications = useMemo(
() => (applicationData?.applications ?? []).map((a) => a.id),
[applicationData],
);
const [{ data: tokenData }] = useTokensQuery({
variables: {
limit: 100,
},
const { tokens } = useSearchTokens({
address: debouncedTokenId,
});
const tokens = useMemo(
() =>
(tokenData?.tokens ?? []).map(
(a) => `${a.symbol} - ${a.name} - ${a.id}`,
),
[tokenData],
);

return (
<>
Expand Down Expand Up @@ -85,6 +70,7 @@ const SendTransaction: FC<DepositProps> = ({
applications={applications}
isLoadingApplications={fetching}
onSearchApplications={setApplicationId}
onSearchTokens={setTokenId}
/>
) : depositType === "ether" ? (
<EtherDepositForm
Expand Down
24 changes: 24 additions & 0 deletions apps/web/src/hooks/useSearchApplications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import { useApplicationsQuery } from "../graphql";

export const useSearchApplications = ({
address,
limit,
}: {
address?: string;
limit?: number;
}) => {
const [{ data: applicationData, fetching }] = useApplicationsQuery({
variables: {
limit: limit ?? 10,
where: {
id_containsInsensitive: address ?? "",
},
},
});
const applications = React.useMemo(
() => (applicationData?.applications ?? []).map((a) => a.id),
[applicationData],
);
return { applications, fetching };
};
27 changes: 27 additions & 0 deletions apps/web/src/hooks/useSearchTokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";
import { useTokensQuery } from "../graphql";

export const useSearchTokens = ({
address,
limit,
}: {
address?: string;
limit?: number;
}) => {
const [{ data: tokenData, fetching }] = useTokensQuery({
variables: {
limit: limit ?? 10,
where: {
id_containsInsensitive: address ?? "",
},
},
});
const tokens = React.useMemo(
() =>
(tokenData?.tokens ?? []).map(
(a) => `${a.symbol} - ${a.name} - ${a.id}`,
),
[tokenData],
);
return { tokens, fetching };
};
49 changes: 37 additions & 12 deletions apps/web/test/components/sendTransaction.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { afterAll, describe, it } from "vitest";
import withMantineTheme from "../utils/WithMantineTheme";
import SendTransaction from "../../src/components/sendTransaction";

import withMantineTheme from "../utils/WithMantineTheme";
const Component = withMantineTheme(SendTransaction);

vi.mock("../../src/graphql", async () => {
Expand Down Expand Up @@ -173,37 +172,63 @@ describe("SendTransaction component", () => {
});
});

it("should initially query 100 tokens", async () => {
it("should initially query 10 tokens with no predefined search", async () => {
const mockedFn = vi.fn().mockReturnValue([{ data: {} }]);
const graphqlModule = await import("../../src/graphql");
graphqlModule.useTokensQuery = vi.fn().mockImplementation(mockedFn);

render(<Component />);
render(<Component initialDepositType="input" />);

expect(mockedFn).toHaveBeenCalledWith({
variables: {
limit: 100,
limit: 10,
where: {
id_containsInsensitive: "",
},
},
});
});

it("should not query tokens more than once", async () => {
it("should query tokens with given search id, using debouncing", async () => {
render(<Component initialDepositType="erc20" />);

const mockedFn = vi.fn().mockReturnValue([{ data: {} }]);
const graphqlModule = await import("../../src/graphql");
graphqlModule.useTokensQuery = vi.fn().mockImplementation(mockedFn);

render(<Component initialDepositType="erc20" />);

const tokenAutocomplete = screen.queryByTestId(
const tokenInputForm = screen.queryByTestId(
"erc20Address",
) as HTMLFormElement;
const search =
"SIM20 - SimpleERC20 - 0x059c7507b973d1512768c06f32a813bc93d83eb2";
const formattedValue = search.substring(search.indexOf("0x"));

fireEvent.change(tokenAutocomplete, {
fireEvent.change(tokenInputForm, {
target: {
value: "SIM20 - SimpleERC20 - 0x059c7507b973d1512768c06f32a813bc93d83eb2",
value: formattedValue,
},
});

expect(mockedFn).toHaveBeenCalledWith({
variables: {
limit: 10,
where: {
id_containsInsensitive: "",
},
},
});

expect(mockedFn).toHaveBeenCalledOnce();
await waitFor(() => expect(mockedFn).toHaveBeenCalledTimes(2), {
timeout: 500,
});

expect(mockedFn).toHaveBeenCalledWith({
variables: {
limit: 10,
where: {
id_containsInsensitive: formattedValue,
},
},
});
});
});
56 changes: 30 additions & 26 deletions packages/ui/src/ERC20DepositForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import {
Textarea,
UnstyledButton,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { useForm } from "@mantine/form";
import { FC, useEffect, useMemo, useState } from "react";
import { useDisclosure } from "@mantine/hooks";
import { isEmpty } from "ramda";
import { FC, useEffect, useState } from "react";
import {
TbAlertCircle,
TbCheck,
Expand Down Expand Up @@ -65,28 +66,21 @@ export const transactionButtonState = (
};

export interface ERC20DepositFormProps {
tokens: string[];
applications: string[];
isLoadingApplications: boolean;
onSearchApplications: (applicationId: string) => void;
tokens: string[];
onSearchTokens: (tokenId: string) => void;
}

export const ERC20DepositForm: FC<ERC20DepositFormProps> = (props) => {
const {
tokens,
applications,
isLoadingApplications,
onSearchApplications,
tokens,
onSearchTokens,
} = props;
const tokenAddresses = useMemo(
() =>
tokens.map((token) => {
const addressIndex = token.indexOf("0x");
const address = getAddress(token.substring(addressIndex));
return `${token.substring(0, addressIndex)}${address}`;
}),
[tokens],
);

const [advanced, { toggle: toggleAdvanced }] = useDisclosure(false);

Expand All @@ -96,18 +90,28 @@ export const ERC20DepositForm: FC<ERC20DepositFormProps> = (props) => {
const [decimals, setDecimals] = useState<number | undefined>();

const form = useForm({
validateInputOnBlur: true,
validateInputOnChange: true,
initialValues: {
application: "",
erc20Address: "",
amount: "",
execLayerData: "0x",
},
validate: {
application: (value) =>
value !== "" && isAddress(value) ? null : "Invalid application",
erc20Address: (value) =>
value !== "" ? null : "Invalid ERC20 address",
application: (value) => {
if (isEmpty(value)) return `Please input ERC20 Address`;
if (!isAddress(value)) {
return `Invalid Application address`;
}
return null;
},
erc20Address: (value) => {
if (isEmpty(value)) return `Please input ERC20 Address`;
if (!isAddress(value)) {
return `Invalid ERC20 address`;
}
return null;
},
amount: (value) =>
value !== "" && Number(value) > 0 ? null : "Invalid amount",
execLayerData: (value) =>
Expand Down Expand Up @@ -164,6 +168,8 @@ export const ERC20DepositForm: FC<ERC20DepositFormProps> = (props) => {
}
}, [erc20.data]);

useEffect(() => {}, [tokens]);

const symbol = erc20.data?.[1].result as string | undefined;
const allowance = erc20.data?.[2].result as bigint | undefined;
const balance = erc20.data?.[3].result as bigint | undefined;
Expand Down Expand Up @@ -254,13 +260,9 @@ export const ERC20DepositForm: FC<ERC20DepositFormProps> = (props) => {
}}
/>

{!form.errors.application &&
{isAddress(applicationAddress) &&
applicationAddress !== zeroAddress &&
!applications.some(
(a) =>
a.toLowerCase() ===
applicationAddress.toLowerCase(),
) && (
!applications.length && (
<Alert
variant="light"
color="yellow"
Expand All @@ -285,12 +287,14 @@ export const ERC20DepositForm: FC<ERC20DepositFormProps> = (props) => {
nextValue.indexOf("0x"),
);
form.setFieldValue("erc20Address", formattedValue);
onSearchTokens(formattedValue);
}}
/>

{!form.errors.erc20Address &&
{isAddress(erc20Address) &&
erc20Address !== zeroAddress &&
!tokenAddresses.some((t) => t.includes(erc20Address)) && (
!tokens.length &&
!erc20.isLoading && (
<Alert
variant="light"
color="yellow"
Expand Down
12 changes: 6 additions & 6 deletions packages/ui/src/RawInputForm.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { FC, useEffect, useMemo } from "react";
import {
useInputBoxAddInput,
usePrepareInputBoxAddInput,
} from "@cartesi/rollups-wagmi";
import {
Alert,
Autocomplete,
Button,
Collapse,
Group,
Loader,
Stack,
Textarea,
Autocomplete,
Alert,
Loader,
} from "@mantine/core";
import { useForm } from "@mantine/form";
import { TbCheck, TbAlertCircle } from "react-icons/tb";
import { FC, useEffect, useMemo } from "react";
import { TbAlertCircle, TbCheck } from "react-icons/tb";
import {
BaseError,
getAddress,
isAddress,
isHex,
toHex,
zeroAddress,
BaseError,
} from "viem";
import { useWaitForTransaction } from "wagmi";
import { TransactionProgress } from "./TransactionProgress";
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
export { Card } from "./Card";
export { ERC20DepositForm } from "./ERC20DepositForm";
export { EtherDepositForm } from "./EtherDepositForm";
export {
InputContent,
InputDetails,
NoticeContent,
ReportContent,
VoucherContent,
} from "./InputDetails";
export { ERC20DepositForm } from "./ERC20DepositForm";
export { EtherDepositForm } from "./EtherDepositForm";
export { RawInputForm } from "./RawInputForm";
export { Summary } from "./Summary";
export { SummaryCard } from "./SummaryCard";
export { TransactionProgress } from "./TransactionProgress";
export { Card } from "./Card";
Loading

0 comments on commit 37045ff

Please sign in to comment.