diff --git a/apps/web/graphql/queries.graphql b/apps/web/graphql/queries.graphql index bcd825002..26f7224b7 100644 --- a/apps/web/graphql/queries.graphql +++ b/apps/web/graphql/queries.graphql @@ -85,6 +85,12 @@ query tokens($limit: Int, $where: TokenWhereInput) { } } +query multiTokens($limit: Int, $where: MultiTokenWhereInput) { + multiTokens(limit: $limit, where: $where) { + id + } +} + fragment ApplicationItem on Application { id owner diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index 7320cb442..39bf7678d 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -1,5 +1,6 @@ import { ColorSchemeScript } from "@mantine/core"; import "@mantine/core/styles.css"; +import { Notifications } from "@mantine/notifications"; import "@mantine/notifications/styles.css"; import { Analytics } from "@vercel/analytics/react"; import { Metadata } from "next"; @@ -34,7 +35,10 @@ const Layout: FC = ({ children }) => { - {children} + <> + + {children} + diff --git a/apps/web/src/components/BlockExplorerLink.tsx b/apps/web/src/components/BlockExplorerLink.tsx new file mode 100644 index 000000000..c3f3f1ce1 --- /dev/null +++ b/apps/web/src/components/BlockExplorerLink.tsx @@ -0,0 +1,45 @@ +import { Anchor, Group, Text, rem } from "@mantine/core"; +import { anyPass, equals } from "ramda"; +import { FC } from "react"; +import { TbExternalLink } from "react-icons/tb"; +import { useConfig } from "wagmi"; + +interface BlockExplorerLinkProps { + value: string; + type: "tx" | "block" | "address"; +} + +const isTxOrAddress = anyPass([equals("tx"), equals("address")]); + +/** + * + * Works in conjuction with Wagmi. It requires a Wagmi-Provider to work as expected. + * When running devnet it will not render a block-explorer link. + * + */ +export const BlockExplorerLink: FC = ({ + value, + type, +}) => { + const config = useConfig(); + const explorerUrl = config.chains[0].blockExplorers?.default.url; + + if (!explorerUrl) return; + + const shouldShorten = isTxOrAddress(type); + + const text = shouldShorten + ? `${value.slice(0, 8)}...${value.slice(-6)}` + : value; + + const href = `${explorerUrl}/${type}/${value}`; + + return ( + + + {text} + + + + ); +}; diff --git a/apps/web/src/components/sendTransaction.tsx b/apps/web/src/components/sendTransaction.tsx index 191f299e4..30afe9f32 100644 --- a/apps/web/src/components/sendTransaction.tsx +++ b/apps/web/src/components/sendTransaction.tsx @@ -1,5 +1,7 @@ "use client"; import { + DepositFormSuccessData, + ERC1155DepositForm, ERC20DepositForm, ERC721DepositForm, EtherDepositForm, @@ -7,16 +9,19 @@ import { } from "@cartesi/rollups-explorer-ui"; import { Select } from "@mantine/core"; import { useDebouncedValue } from "@mantine/hooks"; +import { notifications } from "@mantine/notifications"; import { FC, useCallback, useState } from "react"; import { useSearchApplications } from "../hooks/useSearchApplications"; +import { useSearchMultiTokens } from "../hooks/useSearchMultiTokens"; import { useSearchTokens } from "../hooks/useSearchTokens"; -import { notifications } from "@mantine/notifications"; +import { BlockExplorerLink } from "./BlockExplorerLink"; export type DepositType = | "ether" | "erc20" | "erc721" | "erc1155" + | "erc1155Batch" | "relay" | "input"; @@ -24,21 +29,34 @@ interface DepositProps { initialDepositType?: DepositType; } +const DEBOUNCE_TIME = 400 as const; + const SendTransaction: FC = ({ initialDepositType = "ether", }) => { const [depositType, setDepositType] = useState(initialDepositType); const [applicationId, setApplicationId] = useState(""); + const [multiTokenId, setMultiTokenId] = useState(""); const [tokenId, setTokenId] = useState(""); - const [debouncedApplicationId] = useDebouncedValue(applicationId, 400); - const [debouncedTokenId] = useDebouncedValue(tokenId, 400); + const [debouncedApplicationId] = useDebouncedValue( + applicationId, + DEBOUNCE_TIME, + ); + const [debouncedTokenId] = useDebouncedValue(tokenId, DEBOUNCE_TIME); + const [debouncedMultiTokenId] = useDebouncedValue( + multiTokenId, + DEBOUNCE_TIME, + ); const { applications, fetching } = useSearchApplications({ address: debouncedApplicationId, }); const { tokens } = useSearchTokens({ address: debouncedTokenId, }); + const { multiTokens } = useSearchMultiTokens({ + address: debouncedMultiTokenId, + }); const onDepositErc721 = useCallback(() => { notifications.show({ @@ -48,6 +66,33 @@ const SendTransaction: FC = ({ }); }, []); + const onSuccess = useCallback( + ({ receipt, type }: DepositFormSuccessData) => { + const message = receipt?.transactionHash + ? { + message: ( + + ), + title: `${type} transfer completed`, + } + : { message: `${type} transfer completed.` }; + + notifications.show({ + withCloseButton: true, + autoClose: false, + color: "green", + ...message, + }); + + setMultiTokenId(""); + setApplicationId(""); + }, + [], + ); + return ( <>