Skip to content

Commit

Permalink
Adds contacts logic to nfts (#3252)
Browse files Browse the repository at this point in the history
* Adds contacts logic to nfts

* update
  • Loading branch information
hkirat authored Mar 13, 2023
1 parent bdc58bd commit 31b677d
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ import { useIsValidAddress } from "./Send";

let debouncedTimer = 0;

export interface SendData {
address: string;
username?: string;
image?: string;
uuid?: string;
walletName?: string;
}

const useStyles = makeStyles((theme: any) =>
createStyles({
hoverParent: {
Expand Down Expand Up @@ -84,21 +92,25 @@ const useStyles = makeStyles((theme: any) =>

type AddressSelectorContext = {
blockchain: Blockchain;
token: TokenDataWithPrice;
name: string;
onSelect: (sendData: SendData) => void;
};

const AddressSelectorContext =
React.createContext<AddressSelectorContext | null>(null);

export function AddressSelectorProvider(props: {
blockchain: Blockchain;
token: TokenDataWithPrice;
name: string;
onSelect: (sendData: SendData) => void;
children: any;
}) {
return (
<AddressSelectorContext.Provider
value={{
blockchain: props.blockchain,
token: props.token,
name: props.name,
onSelect: props.onSelect,
}}
>
{props.children}
Expand Down Expand Up @@ -127,6 +139,7 @@ export const AddressSelectorLoader = ({
// (rather than aggregate mode).
const activePublicKey = useActiveWallet().publicKey;
const publicKeyStr = publicKey ?? activePublicKey;
const { push } = useNavigation();
const [token] = useLoader(
blockchainTokenData({
publicKey: publicKeyStr,
Expand All @@ -136,23 +149,70 @@ export const AddressSelectorLoader = ({
null
);
if (!token) return null;
return <AddressSelector blockchain={blockchain} token={token} />;
return (
<AddressSelector
blockchain={blockchain}
name={token.ticker}
onSelect={(sendData) => {
push("send", {
blockchain,
token,
to: sendData,
});
}}
/>
);
};

export const TokenAddressSelector = (props: any) => {
const { push } = useNavigation();

return (
<AddressSelector
{...props}
onSelect={(sendData) => {
push("send", {
blockchain: props.blockchain,
token: props.token,
to: sendData,
});
}}
/>
);
};

export const NftAddressSelector = (props: any) => {
const { push } = useNavigation();

return (
<AddressSelector
{...props}
onSelect={(sendData) => {
push("send", {
blockchain: props.blockchain,
token: props.token,
to: sendData,
});
}}
/>
);
};

export const AddressSelector = ({
blockchain,
token,
name,
onSelect,
}: {
blockchain: Blockchain;
token: TokenDataWithPrice;
name: string;
onSelect: (sendData: SendData) => void;
}) => {
const classes = useStyles();
const nav = useNavigationEphemeral();
const [inputContent, setInputContent] = useState("");
const { provider: solanaProvider } = useAnchorContext();
const ethereumCtx = useEthereumCtx();
const [searchResults, setSearchResults] = useState<RemoteUserData[]>([]);
const { push } = useNavigation();
const { isValidAddress, normalizedAddress } = useIsValidAddress(
blockchain,
inputContent,
Expand All @@ -162,14 +222,18 @@ export const AddressSelector = ({

useEffect(() => {
const prev = nav.title;
nav.setOptions({ headerTitle: `Send ${token.ticker}` });
nav.setOptions({ headerTitle: `Send ${name}` });
return () => {
nav.setOptions({ headerTitle: prev });
};
}, []);

return (
<AddressSelectorProvider blockchain={blockchain} token={token}>
<AddressSelectorProvider
blockchain={blockchain}
name={name}
onSelect={onSelect}
>
<div className={classes.container}>
<div className={classes.topHalf}>
<SearchInput
Expand Down Expand Up @@ -205,15 +269,11 @@ export const AddressSelector = ({
(result) => result.publicKey === inputContent
)
);
push("send", {
blockchain,
token,
to: {
address: normalizedAddress || inputContent,
username: user?.username,
image: user?.image,
uuid: user?.id,
},
onSelect({
address: normalizedAddress || inputContent,
username: user?.username,
image: user?.image,
uuid: user?.id,
});
}}
disabled={!isValidAddress}
Expand Down Expand Up @@ -504,8 +564,7 @@ const AddressListItem = ({
}) => {
const theme = useCustomTheme();
const classes = useStyles();
const { push } = useNavigation();
const { blockchain, token } = useAddressSelectorContext();
const { onSelect } = useAddressSelectorContext();

return (
<ListItemButton
Expand All @@ -514,16 +573,12 @@ const AddressListItem = ({
if (!address) {
return;
}
push("send", {
blockchain,
token,
to: {
address: address,
username: user.username,
walletName: user.walletName,
image: user.image,
uuid: user.uuid,
},
onSelect({
address: address,
username: user.username,
walletName: user.walletName,
image: user.image,
uuid: user.uuid,
});
}}
style={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import { SearchableTokenTables } from "../../common/TokenTable";
import { Swap, SwapSelectToken } from "../../Unlocked/Swap";

import {
AddressSelector,
AddressSelectorLoader,
NftAddressSelector,
TokenAddressSelector,
} from "./TokensWidget/AddressSelector";
import { Deposit } from "./TokensWidget/Deposit";
import { Ramp } from "./TokensWidget/Ramp";
Expand Down Expand Up @@ -136,6 +137,7 @@ function SendButton({
publicKey?: string;
}) {
const theme = useCustomTheme();

return (
<TransferButton
label="Send"
Expand Down Expand Up @@ -176,7 +178,7 @@ function SendButton({
},
{
name: "select-user",
component: (props: any) => <AddressSelector {...props} />,
component: (props: any) => <TokenAddressSelector {...props} />,
title: "",
},
{
Expand Down
77 changes: 61 additions & 16 deletions packages/app-extension/src/components/Unlocked/Nfts/Detail.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type CSSProperties, useEffect, useState } from "react";
import React, { type CSSProperties, useEffect, useState } from "react";
import type { Nft } from "@coral-xyz/common";
import {
AVATAR_BASE_URL,
Expand Down Expand Up @@ -41,7 +41,7 @@ import {
useSolanaExplorer,
useUser,
} from "@coral-xyz/recoil";
import { useCustomTheme } from "@coral-xyz/themes";
import { styles, useCustomTheme } from "@coral-xyz/themes";
import { Whatshot } from "@mui/icons-material";
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
import { Button, IconButton, Typography } from "@mui/material";
Expand All @@ -54,6 +54,7 @@ import {
} from "recoil";

import { ApproveTransactionDrawer } from "../../common/ApproveTransactionDrawer";
import { CopyablePublicKey } from "../../common/CopyablePublicKey";
import {
CloseButton,
useDrawerContext,
Expand All @@ -62,8 +63,11 @@ import {
import {
NavStackEphemeral,
NavStackScreen,
useNavigation as useNavigationEphemeral,
} from "../../common/Layout/NavStack";
import PopoverMenu from "../../common/PopoverMenu";
import type { SendData } from "../Balances/TokensWidget/AddressSelector";
import { AddressSelector } from "../Balances/TokensWidget/AddressSelector";
import { SendEthereumConfirmationCard } from "../Balances/TokensWidget/Ethereum";
import {
Error as ErrorConfirmation,
Expand Down Expand Up @@ -381,15 +385,20 @@ function SendButton({
<WithDrawer openDrawer={openDrawer} setOpenDrawer={setOpenDrawer}>
<div style={{ height: "100%" }}>
<NavStackEphemeral
initialRoute={{ name: "send" }}
initialRoute={{ name: "select-address" }}
options={() => ({
title: nft.name ? `${nft.name} / Send` : "Send",
})}
navButtonLeft={<CloseButton onClick={() => setOpenDrawer(false)} />}
>
<NavStackScreen
name="send"
component={() => <SendScreen nft={nft} />}
component={(props) => <SendScreen {...props} nft={nft} />}
/>

<NavStackScreen
name="select-address"
component={() => <NftAddressSelector nft={nft} />}
/>
</NavStackEphemeral>
</div>
Expand All @@ -398,12 +407,38 @@ function SendButton({
);
}

function SendScreen({ nft }: { nft: any }) {
function NftAddressSelector({ nft }: { nft: any }) {
const { push } = useNavigationEphemeral();

return (
<div>
<AddressSelector
onSelect={(sendData: SendData) => {
push("send", {
to: sendData,
});
}}
blockchain={nft.blockchain}
name={nft.name}
/>
</div>
);
}

const useStyles = styles((theme) => ({
horizontalCenter: {
display: "flex",
justifyContent: "center",
},
}));

function SendScreen({ nft, to }: { nft: any; to: SendData }) {
const background = useBackgroundClient();
const { close } = useDrawerContext();
const { provider: solanaProvider } = useAnchorContext();
const classes = useStyles();
const ethereumCtx = useEthereumCtx();
const [destinationAddress, setDestinationAddress] = useState("");
const destinationAddress = to.address;
const [openConfirm, setOpenConfirm] = useState(false);
const [wasSent, setWasSent] = useState(false);
const { isValidAddress, isErrorAddress } = useIsValidAddress(
Expand Down Expand Up @@ -446,16 +481,12 @@ function SendScreen({ nft }: { nft: any }) {
>
<div>
<Image nft={nft} />
<TextInput
autoFocus
placeholder={`Recipient's ${toTitleCase(nft.blockchain)} Address`}
value={destinationAddress}
setValue={(e) => setDestinationAddress(e.target.value)}
error={isErrorAddress}
inputProps={{
name: "to",
}}
/>
<div className={classes.horizontalCenter} style={{ marginTop: 4 }}>
Sending to
</div>
<div className={classes.horizontalCenter} style={{ marginTop: 4 }}>
<CopyablePublicKey publicKey={to?.address} />
</div>
</div>
<div
style={{
Expand Down Expand Up @@ -492,6 +523,13 @@ function SendScreen({ nft }: { nft: any }) {
decimals: 0, // Are there any NFTs that don't use decimals 0?
mint: nft.mint,
}}
destinationUser={
(to && to.uuid && to.username && to.image
? to
: undefined) as React.ComponentProps<
typeof SendSolanaConfirmationCard
>["destinationUser"]
}
destinationAddress={destinationAddress}
amount={BigNumber.from(1)}
onComplete={() => setWasSent(true)}
Expand All @@ -505,6 +543,13 @@ function SendScreen({ nft }: { nft: any }) {
address: nft.contractAddress,
tokenId: nft.tokenId,
}}
destinationUser={
(to && to.uuid && to.username && to.image
? to
: undefined) as React.ComponentProps<
typeof SendEthereumConfirmationCard
>["destinationUser"]
}
destinationAddress={destinationAddress}
amount={BigNumber.from(1)}
onComplete={() => setWasSent(true)}
Expand Down

0 comments on commit 31b677d

Please sign in to comment.