Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/display address external link #221

Merged
38 changes: 38 additions & 0 deletions components/01-atoms/BlockExplorerExternalLinkButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ExternalLinkIcon } from "@/components/01-atoms";
import { EthereumAddress } from "@/lib/shared/types";
import { useNetwork } from "wagmi";

export const BlockExplorerExternalLinkButton = ({
address,
label,
}: {
address: EthereumAddress;
label?: string;
}) => {
const { chain } = useNetwork();

if (!address) return null;

const displayEllipsedAddress = address.getEllipsedAddress();
eduramme marked this conversation as resolved.
Show resolved Hide resolved

const blockExplorer = `${
chain?.blockExplorers?.default.url
}/address/${address?.toString()}`;
0xneves marked this conversation as resolved.
Show resolved Hide resolved

return (
<div className="flex">
<a
href={blockExplorer}
target="_blank"
className="flex gap-1 items-center justify-start"
>
<h3 className="text-sm font-medium text-[#A3A9A5]">
{label ? label : displayEllipsedAddress}
0xneves marked this conversation as resolved.
Show resolved Hide resolved
</h3>
<div className="p-1">
<ExternalLinkIcon className="dark:text-[#A3A9A5] text-[#AABE13] font-medium" />
</div>
</a>
</div>
);
};
7 changes: 5 additions & 2 deletions components/01-atoms/LoadingIndicator.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import React, { HTMLProps } from "react";
import { HTMLProps } from "react";

export const LoadingIndicator = (props: HTMLProps<HTMLDivElement>) => (
<div {...props} className="animate-spin rounded-full h-4 w-4 border-t-2 dark:border-white border-black"></div>
<div
{...props}
className="animate-spin rounded-full h-4 w-4 border-t-2 dark:border-white border-black"
/>
);
2 changes: 1 addition & 1 deletion components/01-atoms/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const SearchBar = () => {
setUserJustValidatedInput(true);
}
} else if (inputAddress && !authenticatedUserAddress) {
toast.error("Cannot get ENS address without connect your wallet");
toast.error("Cannot get ENS address without connecting your wallet");
}
};

Expand Down
1 change: 1 addition & 0 deletions components/01-atoms/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/** Atoms */
export * from "./ApprovedTokenCards";
export * from "./BlockExplorerExternalLinkButton";
export * from "./ConnectWallet";
export * from "./DisconnectWallet";
export * from "./ENSAvatar";
Expand Down
31 changes: 8 additions & 23 deletions components/02-molecules/EnsNameAndAddressWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { CopyAdressButton } from "@/components/02-molecules";
import { ENSAvatar, ExternalLinkIcon } from "@/components/01-atoms";
import {
BlockExplorerExternalLinkButton,
ENSAvatar,
} from "@/components/01-atoms";
import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser";
import { useEnsData } from "@/lib/client/hooks/useENSData";
import React from "react";
import { useNetwork } from "wagmi";

export const EnsNameAndAddressWallet = () => {
const { authenticatedUserAddress } = useAuthenticatedUser();
Expand All @@ -12,14 +13,8 @@ export const EnsNameAndAddressWallet = () => {
ensAddress: authenticatedUserAddress,
});

const { chain } = useNetwork();

if (!authenticatedUserAddress) return null;

const blockExplorer = `${
chain?.blockExplorers?.default.url
}/address/${authenticatedUserAddress?.toString()}`;

const displayAddress = authenticatedUserAddress?.getEllipsedAddress();

return (
Expand All @@ -42,20 +37,10 @@ export const EnsNameAndAddressWallet = () => {
displayAddress={displayAddress}
/>
</div>
<div className="flex">
<a
href={blockExplorer}
target="_blank"
className="flex gap-1 items-center justify-start"
>
<h3 className="text-sm font-medium text-[#A3A9A5] ">
View on explorer
</h3>
<div className="p-1">
<ExternalLinkIcon className="dark:text-[#A3A9A5] text-[#AABE13] font-medium" />
</div>
</a>
</div>
<BlockExplorerExternalLinkButton
address={authenticatedUserAddress}
label="View on explorer"
/>
</div>
</>
)}
Expand Down
87 changes: 49 additions & 38 deletions components/03-organisms/ApproveTokenCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { BlockExplorerExternalLinkButton } from "@/components/01-atoms";
import {
TokenCard,
TokenCardActionType,
Expand All @@ -13,7 +14,7 @@ import { SWAPLACE_SMART_CONTRACT_ADDRESS } from "@/lib/client/constants";
import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser";
import { isTokenSwapApproved } from "@/lib/service/verifyTokensSwapApproval";
import { IApproveTokenSwap } from "@/lib/client/swap-utils";
import { getTokenName } from "@/lib/client/ui-utils";
import { getTokenContractAddress, getTokenName } from "@/lib/client/ui-utils";
import { Token } from "@/lib/shared/types";
import toast from "react-hot-toast";
import { type TransactionReceipt } from "viem";
Expand Down Expand Up @@ -79,13 +80,12 @@ export const ApproveTokenCard = ({
throw new Error("User is not connected to any network");
}

setTokenApprovalStatus(TokenApprovalStatus.APPROVE_IN_YOUR_WALLET);

const approved = await checkForTokenApproval(token);

if (approved) {
toast.success(`${getTokenName(token)} was approved for swap`);
} else {
setTokenApprovalStatus(TokenApprovalStatus.APPROVE_IN_YOUR_WALLET);
await askForTokenApproval(token).then((isApproved) => {
if (typeof isApproved !== "undefined") {
setIsApproved(true);
Expand Down Expand Up @@ -160,52 +160,63 @@ export const ApproveTokenCard = ({
return (
<div
className={cc([
"flex p-4 items-center gap-4 max-h-[68px]",
"flex p-4 items-center max-h-[68px]",
!isApproved
? "bg-[#282B29] hover:bg-[#353836] transition rounded-xl border border-[#353836]"
: "dark:bg-[#DDF23D] bg-[#97a529] rounded-xl disabled cursor-auto pointer-events-none",
])}
onClick={() => handleTokenApproval()}
role="button"
>
<div>
<TokenCard
displayERC20TokensAmount={true}
withSelectionValidation={false}
onClickAction={TokenCardActionType.APPROVE_TOKEN_SWAP}
ownerAddress={authenticatedUserAddress}
styleType={TokenCardStyleType.SMALL}
tokenData={token}
/>
</div>
<div className="flex flex-col gap-1">
<div className="flex">
<p className={!isApproved ? "p-medium-2-dark" : "p-medium-2"}>
{getTokenName(token)}
</p>
<div className="flex gap-4 w-[75%]">
<div>
<TokenCard
displayERC20TokensAmount={true}
withSelectionValidation={false}
onClickAction={TokenCardActionType.APPROVE_TOKEN_SWAP}
ownerAddress={authenticatedUserAddress}
styleType={TokenCardStyleType.SMALL}
tokenData={token}
/>
</div>
<div className="flex p-semibold-dark">
{tokenApprovalStatus === TokenApprovalStatus.CLICK_TO_APPROVE ? (
<p className=" bg-[#505150] p-1.5 w-fit rounded-[4px] min-h-6 items-center flex">
CLICK TO APPROVE
</p>
) : tokenApprovalStatus ===
TokenApprovalStatus.APPROVE_IN_YOUR_WALLET ? (
<p className="bg-[#505150] p-1.5 w-fit rounded-[4px] min-h-6 items-center flex">
APPROVE TRANSACTION REQUEST IN YOUR WALLET
<div className="flex flex-col gap-1">
<div className="flex">
<p className={!isApproved ? "p-medium-2-dark" : "p-medium-2"}>
{getTokenName(token)}
</p>
) : tokenApprovalStatus ===
TokenApprovalStatus.WAITING_BLOCKCHAIN_CONFIRMATION ? (
<p className="bg-[#505150] p-1.5 w-fit rounded-[4px] min-h-6 items-center flex">
WAITING FOR BLOCKCHAIN CONFIRMATION
</p>
) : TokenApprovalStatus.APPROVED ? (
<div className="bg-[#505150] p-1.5 w-fit bg-opacity-30 rounded-[4px] min-h-6 items-center flex">
<p className="text-white">APPROVED</p>
</div>
) : null}
</div>
<div className="flex p-semibold-dark">
{tokenApprovalStatus === TokenApprovalStatus.CLICK_TO_APPROVE ? (
<p className=" bg-[#505150] p-1.5 w-fit rounded-[4px] min-h-6 items-center flex">
CLICK TO APPROVE
</p>
) : tokenApprovalStatus ===
TokenApprovalStatus.APPROVE_IN_YOUR_WALLET ? (
<p className="bg-[#505150] p-1.5 w-fit rounded-[4px] min-h-6 items-center flex">
APPROVE TRANSACTION REQUEST IN YOUR WALLET
</p>
) : tokenApprovalStatus ===
TokenApprovalStatus.WAITING_BLOCKCHAIN_CONFIRMATION ? (
<p className="bg-[#505150] p-1.5 w-fit rounded-[4px] min-h-6 items-center flex">
WAITING FOR BLOCKCHAIN CONFIRMATION
</p>
) : TokenApprovalStatus.APPROVED ? (
<div className="bg-[#505150] p-1.5 w-fit bg-opacity-30 rounded-[4px] min-h-6 items-center flex">
<p className="text-white">APPROVED</p>
</div>
) : null}
</div>
</div>
</div>
<div
role="button"
className="flex pointer-events-auto items-center"
onClick={(event) => event.stopPropagation()}
>
<BlockExplorerExternalLinkButton
address={getTokenContractAddress(token)}
/>
</div>
</div>
);
};
17 changes: 17 additions & 0 deletions lib/client/ui-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ERC20,
ERC20WithTokenAmountSelection,
ERC721,
EthereumAddress,
Token,
TokenType,
} from "../shared/types";
Expand Down Expand Up @@ -60,3 +61,19 @@ export const getTokenName = (
return `${token.tokenType} - Token Name Not Found`;
}
};

/**
*
* @param token
* @returns TokenContractAddress from token, returns EthereumAddress type.
*/
export const getTokenContractAddress = (token: Token): EthereumAddress => {
if (!token) throw new Error("Token not defined");
let address: EthereumAddress;
if (!token.contract) {
address = (token as ERC721).contractMetadata?.address;
} else {
address = new EthereumAddress(token.contract as string);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!token.contract) {
address = (token as ERC721).contractMetadata?.address;
} else {
address = new EthereumAddress(token.contract as string);
}
if (!token.contract) {
address = (token as ERC721).contractMetadata?.address;
} else if (typeof token.contract === "string") {
address = new EthereumAddress(token.contract);
}
if (!address) throw new Error(`Token contract address not defined for ${getTokenName(token)}`)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Address is not yet defined so the proposal will not work, I changed in a way to accept undefined as well but throwing for it. Also changed the conditionals into a double ternary

return address;
};