-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: [#3] disable claim button when no more to claim
- extracted parcel nft loading logic
- Loading branch information
Showing
17 changed files
with
411 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import React from 'react'; | ||
import DefaultButton, { DefaultButtonProps } from './common/DefaultButton'; | ||
|
||
export interface ClaimButtonProps extends DefaultButtonProps { | ||
allowance: number; | ||
walletAlreadyClaimed: number; | ||
} | ||
|
||
const ClaimButton = ({ allowance, walletAlreadyClaimed, disabled, ...rest }: ClaimButtonProps) => { | ||
const getClaimButtonText = () => { | ||
if (walletAlreadyClaimed === 0 && allowance === 0) { | ||
return 'CLAIM PLOTS'; | ||
} else if (walletAlreadyClaimed > 0) { | ||
return `${walletAlreadyClaimed} PLOTS CLAIMED`; | ||
} else if (allowance > 0) { | ||
return `CLAIM ${allowance} PLOTS`; | ||
} | ||
return ''; | ||
}; | ||
|
||
return ( | ||
<DefaultButton {...rest} disabled={disabled || allowance === 0}> | ||
{getClaimButtonText()} | ||
</DefaultButton> | ||
); | ||
}; | ||
export default ClaimButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import React from 'react'; | ||
|
||
export interface DefaultButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {} | ||
|
||
const DefaultButton = ({ disabled, ...rest }: DefaultButtonProps) => ( | ||
<button {...rest} disabled={disabled} className={disabled ? 'border-button' : ''} /> | ||
); | ||
export default DefaultButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { ZERO_ADDRESS } from '@citydao/parcel-contracts/dist/src/constants/accounts'; | ||
import { addresses } from '../data/whiteListedAddresses'; | ||
|
||
export const MAX_NFT_TO_MINT = Object.values(addresses).reduce((prev, curr) => prev + curr, 0); | ||
|
||
const AGREEMENT_IPFS_HASH = 'QmUbFb12ZEAyoqGUEsnS8fxh78nowEqNwvn7BbAfryRRay'; | ||
export const AGREEMENT_IPFS_URL = `https://ipfs.io/ipfs/${AGREEMENT_IPFS_HASH}`; | ||
|
||
export const PARCEL0_NFT_CONTRACT_ADDRESSES: { [key: number]: string } = { | ||
1: ZERO_ADDRESS, | ||
4: '0x209723a65844093Ad769d557a22742e0f661959d', | ||
}; | ||
|
||
export enum VIEWS { | ||
'INITIAL_VIEW', | ||
'MINTED_NFTS', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import { ZERO_ADDRESS } from '@citydao/parcel-contracts/dist/src/constants/accounts'; | ||
import { JsonRpcProvider, Provider } from '@ethersproject/providers'; | ||
import { Contract, ContractFactory, Signer } from 'ethers'; | ||
import { useEffect, useMemo, useState } from 'react'; | ||
import useWallet from './useWallet'; | ||
|
||
export interface ContractLoaderHook<C extends Contract, K extends KeyOfGetterFunction<C>> { | ||
contract?: C; | ||
values?: ContractValues<C, K>; | ||
refetch: () => Promise<void>; | ||
} | ||
|
||
export type ContractValues<C extends Contract, K extends KeyOfGetterFunction<C>> = { | ||
[P in K]: Awaited<ReturnType<C[K]>>; | ||
}; | ||
|
||
export type KeyOfType<T, V> = keyof { | ||
[P in keyof T as T[P] extends V ? P : never]: any; | ||
}; | ||
|
||
export type KeyOfGetterFunction<T> = KeyOfType<T, () => any>; | ||
|
||
export const useContractLoader = < | ||
F extends ContractFactory, | ||
C extends FactoryContract<F>, | ||
K extends KeyOfGetterFunction<C>, | ||
>( | ||
factory: F, | ||
address: string, | ||
keys: K[] = [], | ||
): ContractLoaderHook<C, K> => { | ||
const { web3Provider } = useWallet(); | ||
|
||
const contract = useMemo( | ||
() => attachContract<F, C>(factory, address, web3Provider) || undefined, | ||
[factory, address, web3Provider], | ||
); | ||
const [values, setValues] = useState<ContractValues<C, K>>(); | ||
|
||
useEffect(() => { | ||
// noinspection JSIgnoredPromiseFromCall | ||
fetchValues(); | ||
}, [contract]); | ||
|
||
const fetchValues = async () => { | ||
if (!contract) { | ||
setValues(undefined); | ||
return; | ||
} | ||
|
||
const fetchedValues = await Promise.all(keys.map((key) => contract[key]())); | ||
|
||
setValues( | ||
fetchedValues.reduce((acc, fetchedValue, index) => { | ||
acc[keys[index]] = fetchedValue; | ||
return acc; | ||
}, {} as ContractValues<C, K>), | ||
); | ||
}; | ||
|
||
return { contract, values, refetch: fetchValues }; | ||
}; | ||
|
||
export const useInterfaceLoader = <C extends Contract, K extends KeyOfGetterFunction<C>>( | ||
factory: InterfaceFactoryConnector<C>, | ||
address: string, | ||
keys: K[] = [], | ||
): ContractLoaderHook<C, K> => { | ||
const { web3Provider } = useWallet(); | ||
|
||
const contract = useMemo( | ||
() => attachInterface<C>(factory, address, web3Provider) || undefined, | ||
[address, web3Provider], | ||
); | ||
const [values, setValues] = useState<ContractValues<C, K>>(); | ||
|
||
useEffect(() => { | ||
// noinspection JSIgnoredPromiseFromCall | ||
fetchValues(); | ||
}, [contract]); | ||
|
||
const fetchValues = async () => { | ||
if (!contract) { | ||
setValues(undefined); | ||
return; | ||
} | ||
|
||
const fetchedValues = await Promise.all(keys.map((key) => contract[key]())); | ||
|
||
setValues( | ||
fetchedValues.reduce((acc, fetchedValue, index) => { | ||
acc[keys[index]] = fetchedValue; | ||
return acc; | ||
}, {} as ContractValues<C, K>), | ||
); | ||
}; | ||
|
||
return { contract, values, refetch: fetchValues }; | ||
}; | ||
|
||
export interface EthereumProviderHook { | ||
provider: Provider | null; | ||
signer: Signer | null; | ||
} | ||
|
||
export const useEthereumProvider = (): EthereumProviderHook => { | ||
const { web3Provider } = useWallet(); | ||
const signer = web3Provider?.getSigner(); | ||
|
||
return { provider: web3Provider, signer: signer || null }; | ||
}; | ||
|
||
export type FactoryContract<F extends ContractFactory> = Contract & Awaited<ReturnType<F['deploy']>>; | ||
|
||
export const attachContract = <F extends ContractFactory, C extends FactoryContract<F>>( | ||
factory: F, | ||
address: string, | ||
provider: JsonRpcProvider | null, | ||
): C | null => { | ||
if (address === '' || address === ZERO_ADDRESS) { | ||
return null; | ||
} | ||
|
||
const signer = provider?.getSigner(); | ||
if (signer) { | ||
return factory.attach(address).connect(signer) as C; | ||
} | ||
|
||
if (provider) { | ||
return factory.attach(address).connect(provider) as C; | ||
} | ||
|
||
return null; | ||
}; | ||
|
||
export type InterfaceFactoryConnector<C extends Contract> = (address: string, provider: Signer | Provider) => C; | ||
|
||
export const attachInterface = <C extends Contract>( | ||
connect: InterfaceFactoryConnector<C>, | ||
address: string, | ||
provider: JsonRpcProvider | null, | ||
): C | null => { | ||
if (address === '' || address === ZERO_ADDRESS) { | ||
return null; | ||
} | ||
|
||
const signer = provider?.getSigner(); | ||
if (signer) { | ||
return connect(address, signer) as C; | ||
} | ||
|
||
if (provider) { | ||
return connect(address, provider) as C; | ||
} | ||
|
||
return null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { ParcelNFT__factory } from '@citydao/parcel-contracts/dist/types/contracts/factories/ParcelNFT__factory'; | ||
import { ParcelNFT } from '@citydao/parcel-contracts/dist/types/contracts/ParcelNFT'; | ||
import { ContractAddress } from '@citydao/parcel-contracts/src/constants/accounts'; | ||
import { useEffect, useState } from 'react'; | ||
import { addresses } from '../data/whiteListedAddresses'; | ||
import { useContractLoader } from './contractHooks'; | ||
import useWallet from './useWallet'; | ||
|
||
export interface ParcelNFTHook { | ||
parcelNFTDetails: ParcelNFTDetails | null; | ||
refetch: () => Promise<void>; | ||
} | ||
|
||
export interface ParcelNFTDetails { | ||
parcelNFT: ParcelNFT; | ||
totalSupply: number; | ||
walletAlreadyClaimed: number; | ||
allowance: number; | ||
} | ||
|
||
export const useParcelNFT = (contractAddress: ContractAddress): ParcelNFTHook => { | ||
const { account } = useWallet(); | ||
const { | ||
contract: parcelNFT, | ||
values, | ||
refetch: refetchValues, | ||
} = useContractLoader(new ParcelNFT__factory(), contractAddress, ['totalSupply']); | ||
const [walletAlreadyClaimed, setWalletAlreadyClaimed] = useState<number>(0); | ||
|
||
const parcelNFTDetails: ParcelNFTDetails | null = | ||
parcelNFT && values && account | ||
? { | ||
parcelNFT: parcelNFT, | ||
walletAlreadyClaimed, | ||
totalSupply: values.totalSupply.toNumber(), | ||
allowance: addresses[account.toLowerCase()], | ||
} | ||
: null; | ||
|
||
useEffect(() => { | ||
// noinspection JSIgnoredPromiseFromCall | ||
loadFields(); | ||
}, [account, parcelNFT]); | ||
|
||
const loadFields = async () => { | ||
if (!parcelNFT || !account) { | ||
setWalletAlreadyClaimed(0); | ||
return; | ||
} | ||
|
||
const alreadyClaimed = (await parcelNFT.alreadyClaimed(account)).toNumber(); | ||
setWalletAlreadyClaimed(alreadyClaimed); | ||
}; | ||
|
||
const refetch = async () => { | ||
await Promise.all([refetchValues(), loadFields()]); | ||
}; | ||
|
||
return { parcelNFTDetails: parcelNFTDetails, refetch }; | ||
}; |
Oops, something went wrong.