diff --git a/components/ClaimModal/ClaimModal.tsx b/components/ClaimModal/ClaimModal.tsx new file mode 100644 index 0000000..a824324 --- /dev/null +++ b/components/ClaimModal/ClaimModal.tsx @@ -0,0 +1,46 @@ +import { FC, useState } from 'react'; +import Modal from 'react-modal'; + +import { useModal } from '../../hooks/useModal'; + +type ClaimModalProps = { + eligibleNftsCount: number; + onButtonClick: () => void; + onClose: () => void; +}; +export const ClaimModal: FC = ({ eligibleNftsCount, onButtonClick }) => { + const { isClaimModalOpen, handleCloseClaimModal } = useModal(); + const [isTermsAccepted, setIsTermsAccepted] = useState(false); + return ( + +
+ Parcel Zero NFT +
Parcel 0 Claim
+ You are eligible to claim + + {` ${eligibleNftsCount}`} Parcel 0 NFT{eligibleNftsCount > 1 ? 's' : ''}. + + +
+ setIsTermsAccepted(e.target.checked)} + /> + +
+ +
+
+ ); +}; diff --git a/components/ClaimModal/index.tsx b/components/ClaimModal/index.tsx new file mode 100644 index 0000000..e715cf2 --- /dev/null +++ b/components/ClaimModal/index.tsx @@ -0,0 +1 @@ +export * from './ClaimModal'; diff --git a/components/ClaimSuccessModal/ClaimSuccessModal.tsx b/components/ClaimSuccessModal/ClaimSuccessModal.tsx new file mode 100644 index 0000000..1fcd2da --- /dev/null +++ b/components/ClaimSuccessModal/ClaimSuccessModal.tsx @@ -0,0 +1,37 @@ +import { FC } from 'react'; +import Modal from 'react-modal'; + +import { useModal } from '../../hooks/useModal'; + +type ClaimSuccessModalProps = { + eligibleNftsCount: number; +}; +export const ClaimSuccessModal: FC = ({ eligibleNftsCount }) => { + const { isClaimSuccessModalOpen, handleCloseClaimSuccessModal } = useModal(); + return ( + +
+ Parcel Zero NFT +
Parcel 0 Claim
+
+ Success! You just claimed + + {` ${eligibleNftsCount}`} Parcel 0 Plot{eligibleNftsCount > 1 ? 's' : ''}. + +

+ Plot location will be revealed on June 15th, +
2022. +

+
+ +
+
+ ); +}; diff --git a/components/ClaimSuccessModal/index.tsx b/components/ClaimSuccessModal/index.tsx new file mode 100644 index 0000000..2e4dd92 --- /dev/null +++ b/components/ClaimSuccessModal/index.tsx @@ -0,0 +1 @@ +export * from './ClaimSuccessModal'; diff --git a/context/ModalContext.tsx b/context/ModalContext.tsx new file mode 100644 index 0000000..381a4bd --- /dev/null +++ b/context/ModalContext.tsx @@ -0,0 +1,51 @@ +import { createContext, useState, ReactNode } from 'react'; + +interface ModalContextData { + isClaimModalOpen: boolean; + handleOpenClaimModal(): void; + handleCloseClaimModal(): void; + isClaimSuccessModalOpen: boolean; + handleOpenClaimSuccessModal(): void; + handleCloseClaimSuccessModal(): void; +} +interface ModalProviderProps { + children: ReactNode; +} + +export const ModalContext = createContext({} as ModalContextData); + +export function ModalProvider({ children }: ModalProviderProps) { + const [isClaimModalOpen, setisClaimModalOpen] = useState(false); + const [isClaimSuccessModalOpen, setisClaimSuccessModalOpen] = useState(false); + + function handleOpenClaimModal() { + setisClaimModalOpen(true); + } + + function handleCloseClaimModal() { + setisClaimModalOpen(false); + } + + function handleOpenClaimSuccessModal() { + setisClaimSuccessModalOpen(true); + } + + function handleCloseClaimSuccessModal() { + setisClaimSuccessModalOpen(false); + } + + return ( + + {children} + + ); +} diff --git a/hooks/useModal.tsx b/hooks/useModal.tsx new file mode 100644 index 0000000..d22de2e --- /dev/null +++ b/hooks/useModal.tsx @@ -0,0 +1,9 @@ +import { useContext } from 'react'; + +import { ModalContext } from '../context/ModalContext'; + +export function useModal() { + const context = useContext(ModalContext); + + return context; +} diff --git a/package.json b/package.json index 65cfeb7..9a57965 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "@citydao/parcel-contracts": "^0.0.4", + "@types/react-modal": "^3.13.1", "@walletconnect/web3-provider": "^1.7.8", "ethers": "^5.5.1", "joi": "^17.4.2", @@ -23,6 +24,7 @@ "next": "12.0.4", "react": "17.0.2", "react-dom": "17.0.2", + "react-modal": "^3.15.1", "simple-git": "^2.47.0", "web3modal": "^1.9.7" }, diff --git a/pages/_app.tsx b/pages/_app.tsx index 4386ed5..72470bd 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,31 +1,29 @@ -import "../styles/globals.css"; -import { AppProps } from "next/app"; -import Head from "next/head"; -import { AppProvider } from "../context/StateProvider"; +import '../styles/globals.css'; +import { AppProps } from 'next/app'; +import Head from 'next/head'; +import { AppProvider } from '../context/StateProvider'; +import { ModalProvider } from '../context/ModalContext'; +import Modal from 'react-modal'; +Modal.setAppElement('#__next'); function MyApp({ Component, pageProps }: AppProps) { return ( <> CityDAO Parcel-0 Claim Portal - + - + - + + + ); diff --git a/pages/index.tsx b/pages/index.tsx index 9f18de8..d7c35e7 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -3,10 +3,11 @@ import { useState, FC, useEffect } from 'react'; import { NextPage } from 'next'; import { ethers } from 'ethers'; import { Iframe } from '../components/Iframe'; +import { ClaimModal } from '../components/ClaimModal'; +import { ClaimSuccessModal } from '../components/ClaimSuccessModal'; import { ParcelProperties } from '../containers/ParcelProperties'; import useWallet from '../hooks/useWallet'; import { ParcelNFT__factory } from '@citydao/parcel-contracts/dist/types/contracts/factories/ParcelNFT__factory'; - import { getParcelProperties } from '../parcel-properties'; import keccak256 from 'keccak256'; import MerkleTree from 'merkletreejs'; @@ -16,6 +17,8 @@ import { MAX_NFT_TO_MINT } from '../contants'; import { MintedNftsView } from '../components/MintedNftsView'; const PARCEL0_NFT_CONTRACT_ADDRESS = '0x209723a65844093Ad769d557a22742e0f661959d'; const numberOfMintedNFTsSoFar = 1; // TODO trkaplan calculate this value +import { useModal } from '../hooks/useModal'; + interface ConnectButtonProps { enabled?: boolean; onClick?(): void; @@ -40,6 +43,7 @@ function hashToken(address: keyof Addresses, allowance: number) { return Buffer.from(ethers.utils.solidityKeccak256(['address', 'uint256'], [address, allowance]).slice(2), 'hex'); } const Home: NextPage = () => { + const { handleOpenClaimModal, handleCloseClaimModal, handleOpenClaimSuccessModal } = useModal(); const [numberOfMintedNfts, setNumberOfMintedNfts] = useState(0); const [eligibleNftCount, setEligibleNftCount] = useState(0); const [isIframeLoaded, setIsIframeLoaded] = useState(false); @@ -56,6 +60,7 @@ const Home: NextPage = () => { setEligibleNftCount(0); setNumberOfMintedNfts(0); } + // TODO trkaplan memoise tree const tree = new MerkleTree( Object.entries(addresses).map(([address, allowance]) => hashToken(address, allowance)), keccak256, @@ -98,6 +103,8 @@ const Home: NextPage = () => { .allowListMint(eligibleNftCount, allowance, proof) .then((res: any) => { console.log('response', res); + handleCloseClaimModal(); + handleOpenClaimSuccessModal(); }); } else { console.log('Already claimed!'); @@ -128,8 +135,9 @@ const Home: NextPage = () => { .then((result: ethers.BigNumber) => { const numberOfMinted = result.toNumber(); if (allowance > numberOfMinted) { - setEligibleNftCount(1); + setEligibleNftCount(allowance); setNumberOfMintedNfts(0); + setCurrentView(VIEWS.INITIAL_VIEW); // in case user in on the minted nfts view and changes the wallet. } else if (allowance === numberOfMinted) { setNumberOfMintedNfts(numberOfMinted); } @@ -191,7 +199,7 @@ const Home: NextPage = () => { {/* nftCount */}