diff --git a/components/identities/availableIdentities.tsx b/components/identities/availableIdentities.tsx new file mode 100644 index 00000000..a507ad72 --- /dev/null +++ b/components/identities/availableIdentities.tsx @@ -0,0 +1,272 @@ +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import homeStyles from "../../styles/Home.module.css"; +import styles from "../../styles/components/identitiesV1.module.css"; +import { useRouter } from "next/router"; +import IdentityWarnings from "../../components/identities/identityWarnings"; +import IdentityCard from "../../components/identities/identityCard"; +import IdentityActions from "../../components/identities/actions/identityActions"; +import { + useAccount, + useConnect, + useSendTransaction, +} from "@starknet-react/core"; +import IdentityPageSkeleton from "../../components/identities/skeletons/identityPageSkeleton"; +import UpdateProfilePic from "../../components/identities/updateProfilePic"; +import TxConfirmationModal from "../../components/UI/txConfirmationModal"; +import { Identity } from "../../utils/apiWrappers/identity"; +import { formatHexString } from "../../utils/stringService"; +import { getDomainData } from "@/utils/cacheDomainData"; +import { useSearchParams } from "next/navigation"; +import IdentityActionsSkeleton from "@/components/identities/skeletons/identityActionsSkeleton"; +import { hexToDecimal } from "@/utils/feltService"; +import WalletConnect from "@/components/UI/walletConnect"; +import { Connector } from "starknetkit"; +import { FaPlus } from "react-icons/fa"; + +const AvailableIdentities = ({ tokenId }: { tokenId: string }) => { + const router = useRouter(); + const { address } = useAccount(); + //const tokenId: string = router.query.tokenId as string; + const [identity, setIdentity] = useState(); + const [isIdentityADomain, setIsIdentityADomain] = useState< + boolean | undefined + >(); + const [hideActions, setHideActions] = useState(false); + const [isOwner, setIsOwner] = useState(true); + const [isUpdatingPp, setIsUpdatingPp] = useState(false); + const [isTxModalOpen, setIsTxModalOpen] = useState(false); + const [ppTxHash, setPpTxHash] = useState(); + const [ppImageUrl, setPpImageUrl] = useState(""); + const [minting, setMinting] = useState(false); + const searchParams = useSearchParams(); + const mintingInUrl = searchParams.get("minting") === "true"; + const { connectAsync, connectors } = useConnect(); + const [ownedIdentities, setOwnedIdentities] = useState([]); + const randomTokenId: number = Math.floor(Math.random() * 1000000000000); + const [showWalletConnectModal, setShowWalletConnectModal] = + useState(false); + + const callData = useMemo(() => { + return { + contractAddress: process.env.NEXT_PUBLIC_IDENTITY_CONTRACT as string, + entrypoint: "mint", + calldata: [randomTokenId.toString()], + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const { sendAsync: execute } = useSendTransaction({ + calls: [callData], + }); + + useEffect(() => { + if (mintingInUrl) setMinting(true); + else setMinting(false); + }, [mintingInUrl]); + + const endMinting = useCallback(() => { + router.replace(router.asPath.split("?")[0]); + setMinting(false); + setHideActions(false); + }, [router]); + + useEffect(() => { + if (minting && identity) endMinting(); + }, [minting, identity, endMinting]); + + useEffect(() => { + if (!identity || !address) { + setIsOwner(false); + return; + } + setIsOwner(identity.ownerAddress === formatHexString(address)); + }, [identity, address]); + + useEffect(() => { + if (!identity) { + setPpImageUrl(""); + return; + } + + const fetchProfilePic = async () => { + try { + const imgUrl = await identity.getPfpFromVerifierData(); + setPpImageUrl(imgUrl); + } catch (error) { + setPpImageUrl(""); + } + }; + + fetchProfilePic(); + }, [identity]); + + const hideActionsHandler = (state: boolean) => { + if (state == true) { + setHideActions(true); + } else { + setHideActions(false); + } + }; + + const refreshData = useCallback( + () => + fetch(`${process.env.NEXT_PUBLIC_SERVER_LINK}/id_to_data?id=${tokenId}`) + .then(async (response) => { + if (!response.ok) { + throw new Error(await response.text()); + } + return response.json(); + }) + .then((data: IdentityData) => { + if (minting) endMinting(); + setIdentity(new Identity(data)); + setIsIdentityADomain(Boolean(data?.domain)); + }) + .catch(() => { + // Domain data might not be indexed yet, so we check local storage + const domainData = getDomainData(tokenId); + if (domainData) { + setIdentity(new Identity(domainData)); + setIsIdentityADomain(Boolean(domainData?.domain)); + } else { + setIsIdentityADomain(false); + } + }), + [tokenId, minting, endMinting] + ); + + useEffect(() => { + if (minting && tokenId && !identity) { + const interval = setInterval(() => refreshData(), 1000); + return () => clearInterval(interval); + } + }, [minting, tokenId, identity, refreshData]); + + useEffect(() => { + if (tokenId) { + refreshData(); + const timer = setInterval(() => refreshData(), 30e3); + return () => clearInterval(timer); + } + }, [tokenId, refreshData]); + + function mint() { + execute(); + } + useEffect(() => { + if (address) { + // Our Indexer + fetch( + `${ + process.env.NEXT_PUBLIC_SERVER_LINK + }/addr_to_full_ids?addr=${hexToDecimal(address)}` + ) + .then((response) => response.json()) + .then((data) => { + setOwnedIdentities(data.full_ids); + }); + } + }, [address, router.asPath]); + + const connectWallet = async (connector: Connector) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + await connectAsync({ connector }); + localStorage.setItem("SID-connectedWallet", connector.id); + localStorage.setItem("SID-lastUsedConnector", connector.id); + }; + return ( + <> +
+ {isIdentityADomain === undefined ? ( + + ) : !isUpdatingPp ? ( +
+
+
+
+ {ownedIdentities.map((domain, index) => ( + + ))} +
+ +
+
+ <> +
+ setIsUpdatingPp(true)} + ppImageUrl={ppImageUrl} + /> + {!hideActions ? ( + + ) : ( + minting && + )} +
+ + +
+
+
+ ) : ( + setIsUpdatingPp(false)} + openTxModal={() => setIsTxModalOpen(true)} + setPfpTxHash={setPpTxHash} + /> + )} +
+ setIsTxModalOpen(false)} + title="Your new profile picture is being set !" + /> + setShowWalletConnectModal(false)} + open={showWalletConnectModal} + connectors={connectors as Connector[]} + connectWallet={connectWallet} + /> + + ); +}; + +export default AvailableIdentities; diff --git a/pages/identities.tsx b/pages/identities.tsx index ee157b64..f0b49568 100644 --- a/pages/identities.tsx +++ b/pages/identities.tsx @@ -7,7 +7,6 @@ import { useSendTransaction, } from "@starknet-react/core"; import { useEffect, useState } from "react"; -import IdentitiesGallery from "../components/identities/identitiesGalleryV1"; import { useRouter } from "next/router"; import { hexToDecimal } from "../utils/feltService"; import IdentitiesSkeleton from "../components/identities/skeletons/identitiesSkeleton"; @@ -17,6 +16,7 @@ import { NotificationType, TransactionType } from "../utils/constants"; import WalletConnect from "@/components/UI/walletConnect"; import { Connector } from "starknetkit"; import AddButton from "@/components/UI/AddButtonIdentities"; +import AvailableIdentities from "@/components/identities/availableIdentities"; const Identities: NextPage = () => { const { address } = useAccount(); @@ -103,13 +103,13 @@ const Identities: NextPage = () => { return ( <> -
+
{loading ? ( ) : ownedIdentities.length + externalDomains.length === 0 || !address ? ( - <> +

All Your Identities in One Place

@@ -129,45 +129,22 @@ const Identities: NextPage = () => { } width="auto" /> */} - mint() - : () => setShowWalletConnectModal(true) - } radius="8px" -> - ADD IDENTITIES - - -
- - ) : ( -
- -
- {/* } + mint() : () => setShowWalletConnectModal(true) } - width="auto" - /> */} - mint() - : () => setShowWalletConnectModal(true) - } radius="8px" -> - ADD IDENTITIES + radius="8px" + > + ADD IDENTITIES
+ ) : ( +
+ +
)}
diff --git a/pages/identities/[tokenId].tsx b/pages/identities/[tokenId].tsx index 78115ed2..c8eb175e 100644 --- a/pages/identities/[tokenId].tsx +++ b/pages/identities/[tokenId].tsx @@ -1,186 +1,22 @@ -import React, { useCallback, useEffect, useState } from "react"; +import React from "react"; +import AvailableIdentities from "@/components/identities/availableIdentities"; import homeStyles from "../../styles/Home.module.css"; -import styles from "../../styles/components/identitiesV1.module.css"; -import { useRouter } from "next/router"; import { NextPage } from "next"; -import IdentityWarnings from "../../components/identities/identityWarnings"; -import IdentityCard from "../../components/identities/identityCard"; -import IdentityActions from "../../components/identities/actions/identityActions"; -import { useAccount } from "@starknet-react/core"; -import IdentityPageSkeleton from "../../components/identities/skeletons/identityPageSkeleton"; -import UpdateProfilePic from "../../components/identities/updateProfilePic"; -import TxConfirmationModal from "../../components/UI/txConfirmationModal"; -import BackButton from "../../components/UI/backButton"; -import { Identity } from "../../utils/apiWrappers/identity"; -import { formatHexString } from "../../utils/stringService"; -import { getDomainData } from "@/utils/cacheDomainData"; -import { useSearchParams } from "next/navigation"; -import IdentityActionsSkeleton from "@/components/identities/skeletons/identityActionsSkeleton"; +import { useRouter } from "next/router"; +import BackButton from "@/components/UI/backButton"; const TokenIdPage: NextPage = () => { const router = useRouter(); - const { address } = useAccount(); - const tokenId: string = router.query.tokenId as string; - const [identity, setIdentity] = useState(); - const [isIdentityADomain, setIsIdentityADomain] = useState< - boolean | undefined - >(); - const [hideActions, setHideActions] = useState(false); - const [isOwner, setIsOwner] = useState(true); - const [isUpdatingPp, setIsUpdatingPp] = useState(false); - const [isTxModalOpen, setIsTxModalOpen] = useState(false); - const [ppTxHash, setPpTxHash] = useState(); - const [ppImageUrl, setPpImageUrl] = useState(""); - const [minting, setMinting] = useState(false); - const searchParams = useSearchParams(); - const mintingInUrl = searchParams.get("minting") === "true"; - - useEffect(() => { - if (mintingInUrl) setMinting(true); - else setMinting(false); - }, [mintingInUrl]); - - const endMinting = useCallback(() => { - router.replace(router.asPath.split("?")[0]); - setMinting(false); - setHideActions(false); - }, [router]); - - useEffect(() => { - if (minting && identity) endMinting(); - }, [minting, identity, endMinting]); - - useEffect(() => { - if (!identity || !address) { - setIsOwner(false); - return; - } - setIsOwner(identity.ownerAddress === formatHexString(address)); - }, [identity, address]); - - useEffect(() => { - if (!identity) { - setPpImageUrl(""); - return; - } - - const fetchProfilePic = async () => { - try { - const imgUrl = await identity.getPfpFromVerifierData(); - setPpImageUrl(imgUrl); - } catch (error) { - setPpImageUrl(""); - } - }; - - fetchProfilePic(); - }, [identity]); - - const hideActionsHandler = (state: boolean) => { - if (state == true) { - setHideActions(true); - } else { - setHideActions(false); - } - }; - - const refreshData = useCallback( - () => - fetch(`${process.env.NEXT_PUBLIC_SERVER_LINK}/id_to_data?id=${tokenId}`) - .then(async (response) => { - if (!response.ok) { - throw new Error(await response.text()); - } - return response.json(); - }) - .then((data: IdentityData) => { - if (minting) endMinting(); - setIdentity(new Identity(data)); - setIsIdentityADomain(Boolean(data?.domain)); - }) - .catch(() => { - // Domain data might not be indexed yet, so we check local storage - const domainData = getDomainData(tokenId); - if (domainData) { - setIdentity(new Identity(domainData)); - setIsIdentityADomain(Boolean(domainData?.domain)); - } else { - setIsIdentityADomain(false); - } - }), - [tokenId, minting, endMinting] - ); - - useEffect(() => { - if (minting && tokenId && !identity) { - const interval = setInterval(() => refreshData(), 1000); - return () => clearInterval(interval); - } - }, [minting, tokenId, identity, refreshData]); - - useEffect(() => { - if (tokenId) { - refreshData(); - const timer = setInterval(() => refreshData(), 30e3); - return () => clearInterval(timer); - } - }, [tokenId, refreshData]); - + const tokenId: string = router.query.tokenId as string; return ( - <> -
- {isIdentityADomain === undefined ? ( - - ) : !isUpdatingPp ? ( -
-
- window.history.back()} /> -
-
- <> -
- setIsUpdatingPp(true)} - ppImageUrl={ppImageUrl} - /> - {!hideActions ? ( - - ) : ( - minting && - )} -
- - -
-
- ) : ( - setIsUpdatingPp(false)} - openTxModal={() => setIsTxModalOpen(true)} - setPfpTxHash={setPpTxHash} - /> - )} +
+
+
+ window.history.back()} /> +
+
- setIsTxModalOpen(false)} - title="Your new profile picture is being set !" - /> - +
); };