Skip to content

Commit

Permalink
Merge pull request #8 from citydaoproject/claim-popups
Browse files Browse the repository at this point in the history
add claim and claim success popups + fix eligible NFT shown on button
  • Loading branch information
mdnorman authored May 12, 2022
2 parents 1960f09 + ed61294 commit 6cf419d
Show file tree
Hide file tree
Showing 13 changed files with 274 additions and 18 deletions.
46 changes: 46 additions & 0 deletions components/ClaimModal/ClaimModal.tsx
Original file line number Diff line number Diff line change
@@ -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<ClaimModalProps> = ({ eligibleNftsCount, onButtonClick }) => {
const { isClaimModalOpen, handleCloseClaimModal } = useModal();
const [isTermsAccepted, setIsTermsAccepted] = useState<boolean>(false);
return (
<Modal
isOpen={isClaimModalOpen}
onRequestClose={handleCloseClaimModal}
overlayClassName="react-modal-overlay"
className="react-modal-content"
>
<div className="claim-popup">
<img src="/citydao-parcel-0-logo.png" alt="Parcel Zero NFT" />
<div className="popup-title">Parcel 0 Claim</div>
You are eligible to claim
<span className="text-primary">
{` ${eligibleNftsCount}`} Parcel 0 NFT{eligibleNftsCount > 1 ? 's' : ''}.
</span>
<img className="parcel-art" src={'/citydao-parcel-0-NFT-Art-sm.png'} alt="" />
<div className="terms">
<input
id="cb1"
type="checkbox"
checked={isTermsAccepted}
onChange={(e) => setIsTermsAccepted(e.target.checked)}
/>
<label htmlFor="cb1">
Accept Parcel 0 <span className="text-primary">Terms & Conditions</span>
</label>
</div>
<button className="btn-accept" disabled={!isTermsAccepted} onClick={onButtonClick}>
AGREE & CLAIM
</button>
</div>
</Modal>
);
};
1 change: 1 addition & 0 deletions components/ClaimModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ClaimModal';
37 changes: 37 additions & 0 deletions components/ClaimSuccessModal/ClaimSuccessModal.tsx
Original file line number Diff line number Diff line change
@@ -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<ClaimSuccessModalProps> = ({ eligibleNftsCount }) => {
const { isClaimSuccessModalOpen, handleCloseClaimSuccessModal } = useModal();
return (
<Modal
isOpen={isClaimSuccessModalOpen}
onRequestClose={handleCloseClaimSuccessModal}
overlayClassName="react-modal-overlay"
className="react-modal-content"
>
<div className="claim-popup">
<img className="parcel-0-logo-md" src="/citydao-parcel-0-logo-md.png" alt="Parcel Zero NFT" />
<div className="popup-title">Parcel 0 Claim</div>
<div className="popup-content">
Success! You just claimed
<span className="text-primary">
{` ${eligibleNftsCount}`} Parcel 0 Plot{eligibleNftsCount > 1 ? 's' : ''}.
</span>
<p>
Plot location will be revealed on June 15th,
<br /> 2022.
</p>
</div>
<button className="btn-close" onClick={handleCloseClaimSuccessModal}>
Close
</button>
</div>
</Modal>
);
};
1 change: 1 addition & 0 deletions components/ClaimSuccessModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ClaimSuccessModal';
51 changes: 51 additions & 0 deletions context/ModalContext.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<ModalContext.Provider
value={{
isClaimModalOpen,
handleOpenClaimModal,
handleCloseClaimModal,
isClaimSuccessModalOpen,
handleOpenClaimSuccessModal,
handleCloseClaimSuccessModal,
}}
>
{children}
</ModalContext.Provider>
);
}
9 changes: 9 additions & 0 deletions hooks/useModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { useContext } from 'react';

import { ModalContext } from '../context/ModalContext';

export function useModal() {
const context = useContext(ModalContext);

return context;
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
},
Expand Down
26 changes: 12 additions & 14 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<Head>
<title>CityDAO Parcel-0 Claim Portal</title>
<meta
name="description"
content="Read and approve the CityDAO Parcel-0 NFT Agreement"
/>
<meta name="description" content="Read and approve the CityDAO Parcel-0 NFT Agreement" />
<link rel="icon" href="/logo.jpeg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin=""
/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
<link
href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@600&family=Inter&display=swap"
rel="stylesheet"
/>
</Head>
<AppProvider>
<Component {...pageProps} />
<ModalProvider>
<Component {...pageProps} />
</ModalProvider>
</AppProvider>
</>
);
Expand Down
16 changes: 13 additions & 3 deletions pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand All @@ -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<number>(0);
const [eligibleNftCount, setEligibleNftCount] = useState<number>(0);
const [isIframeLoaded, setIsIframeLoaded] = useState<boolean>(false);
Expand All @@ -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,
Expand Down Expand Up @@ -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!');
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -191,14 +199,16 @@ const Home: NextPage = () => {
{/* nftCount */}
<button
disabled={!address}
onClick={numberOfMintedNfts === 0 ? claim : showMintedNfts}
onClick={numberOfMintedNfts === 0 ? handleOpenClaimModal : showMintedNfts}
className={numberOfMintedNfts > 0 ? 'border-button default-cursor' : ''}
>
{getClaimButtonText(numberOfMintedNfts, eligibleNftCount)}
</button>
<ParcelProperties parcelProperties={parcelProperties} />
</div>
</div>
<ClaimModal onButtonClick={claim} eligibleNftsCount={eligibleNftCount} />
<ClaimSuccessModal eligibleNftsCount={eligibleNftCount} />
</main>
</>
);
Expand Down
Binary file added public/citydao-parcel-0-NFT-Art-sm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/citydao-parcel-0-logo-md.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
--color-secondary: #b8bbba;
--color-dark-green: #3b865e;
--color-bg: #04100b;
--color-bg2: #E5E5E5;
--color-hover: #d7e5e0;
--color-disabled: #a7a7a7;
--color-disabled-text: gray;
Expand Down Expand Up @@ -307,4 +308,70 @@ button.border-button {
margin-left: 16px;
margin-right: 16px;
margin-bottom: 16px;
}
.claim-popup {
text-align: center;
}
.claim-popup .parcel-0-logo-md {
width: 87px;
}
.parcel-art {
max-width: 338px;
margin-top: 36px;
margin-bottom: 24px;
}
.terms{
margin-bottom: 24px;
font-size: 16px;
}
#cb1{
margin-right: 4px;
vertical-align: middle;
}
.btn-accept{
max-width: 338px;
margin-bottom: 36px;
}
.btn-close {
width: 134px;
margin-bottom: 53px;
margin-top: 55px;
background-color: var(--color-bg2);
}
.popup-title {
font-size: 24px;
color: var(--color-primary);
padding-bottom: 16px;
}
.popup-content {
letter-spacing: 0.3px;
}
.popup-content >p{
margin-top:7px;
}
.text-primary {
color: var(--color-primary);
}

.react-modal-overlay {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;

display: flex;
align-items: center;
justify-content: center;

background: rgba(0,0,0,0.5);
}

.react-modal-content {
position: relative;
max-width: 482px;
width: 100%;
padding-top: 24px;
background: #04110C;
border: 1px solid #00FFA8;
}
Loading

0 comments on commit 6cf419d

Please sign in to comment.