Skip to content

Commit

Permalink
fix ipfs load times
Browse files Browse the repository at this point in the history
  • Loading branch information
divine-comedian committed Sep 14, 2023
1 parent bb3ffa9 commit af91f36
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 130 deletions.
18 changes: 10 additions & 8 deletions components/NFTCard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Image from 'next/image'
import { MintingContractProps } from '../utils/ContractHelper'
import { useParseIpfsImage } from '../utils/AxiosHelper'
import { useState, useEffect } from 'react'
import { useContractRead } from 'wagmi'
import MintingContractJSON from '../artifacts/contracts/MitchMinterSupplyUpgradeable.sol/MitchMinter.json'
import { formatEther } from 'viem'
import { getIpfsImage } from '../utils/AxiosHelper'


interface NFTCardProps {
Expand Down Expand Up @@ -45,11 +45,6 @@ export const NFTCard: React.FC<NFTCardProps> = ({
setToggleText(!toggleText)
}

const newIpfsImage = useParseIpfsImage(tokenId, contractProps)
// const newIpfsData = useParseIpfsData(tokenId, contractProps)

// const tokenName = ipfsData.name
// const tokenDescription = ipfsData.description
const tokenID = tokenId

const maxTokenSupply = useContractRead({
Expand Down Expand Up @@ -91,6 +86,8 @@ export const NFTCard: React.FC<NFTCardProps> = ({
// enabled: false,
// })



useEffect(() => {
setTimeout(() => {
maxTokenSupply.refetch()
Expand Down Expand Up @@ -172,8 +169,13 @@ export const NFTCard: React.FC<NFTCardProps> = ({
}, [tokenInfo, isTokenInfoError])

useEffect(() => {
setIpfsImage(newIpfsImage)
}, [newIpfsImage])
if (image) {
getIpfsImage(image).then((res) => {
setIpfsImage(res)
}
)
}
},[image])

useEffect(() => {
setTokenSymbol(paymentTokenSymbol)
Expand Down
3 changes: 0 additions & 3 deletions components/mint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,10 @@ export const MintModal = ({
userBalance,
nftData
}: MintItems) => {
console.log('nftData', nftData)
const tokenId = itemsArray[0].tokenID
const twitterLink = contractProps.nftExplorerLink + '0x' + contractProps.address + '/' + tokenId
const tokenBatchIds = itemsArray.map((item) => item.tokenID)
const tokenLinks = itemsArray.map((item) => (
console.log('item', nftData[item.tokenID - 1]?.name),
console.log('item', item.tokenID),
<li className="text-purple-600 py-1 text-lg hover:text-purple-700 font-bold" key={item.tokenID}>
{' '}
<a
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@openzeppelin/contracts": "^4.7.2",
"@openzeppelin/contracts-upgradeable": "npm:@openzeppelin/contracts-upgradeable",
"@rainbow-me/rainbowkit": "1",
"@rainbow-me/rainbowkit": "^1.0.11",
"@tailwindcss/forms": "^0.5.2",
"@types/react-modal": "^3.13.1",
"@vercel/analytics": "^1.0.1",
Expand All @@ -43,7 +43,7 @@
"unstated-next": "^1.1.0",
"usehooks-ts": "^2.9.1",
"viem": "1.7.0",
"wagmi": "1",
"wagmi": "1.4.1",
"yarn": "^1.22.19"
},
"devDependencies": {
Expand Down
2 changes: 2 additions & 0 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {infuraProvider} from 'wagmi/providers/infura'
import { constants } from '../utils/constants'
import { Analytics } from '@vercel/analytics/react'
import { jsonRpcProvider } from 'wagmi/providers/jsonRpc'
import { publicProvider } from 'wagmi/providers/public';


const walletConnectId = process.env.WALLET_CONNECT_PROJECT as string
Expand All @@ -30,6 +31,7 @@ if (process.env.NODE_ENV === 'development') {
const { chains, publicClient } = configureChains(appChains, [
infuraProvider({ apiKey: infuraID}),
jsonRpcProvider({ rpc: () => ({ http: NEXT_PUBLIC_GNOSIS_RPC_URL }) }),
publicProvider(),
])

const { connectors } = getDefaultWallets({
Expand Down
5 changes: 3 additions & 2 deletions pages/store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ interface Item {
tokenPrice: string
}

interface nftData {
export interface nftData {
name: string
description: string
image: string
Expand Down Expand Up @@ -143,8 +143,9 @@ const Store = () => {
try {
const allNftData: nftData[] = [];
for(let i = 1; i <= totalTokens; i++) {
const response = await getIpfsData(i, contractProps);
getIpfsData(i, contractProps).then((response) => {
allNftData.push(response);
0 })
}
return allNftData;
} catch (error) {
Expand Down
199 changes: 108 additions & 91 deletions utils/AxiosHelper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import MintingContractJSON from '../artifacts/contracts/MitchMinterSupplyUpgrade
import { useContractRead } from 'wagmi';
import { constants } from './constants';
import { readContract } from '@wagmi/core';
import { nftData } from '../pages/store';

const ipfsGateways = constants.IPFS_GATEWAYS!.split(',');

Expand All @@ -23,7 +24,7 @@ async function getDataFromGateways(path: any) {
throw new Error('All gateways failed');
}

export const getIpfsData = async (tokenId: number, contractProps: MintingContractProps) => {
export const getIpfsData = async (tokenId: number, contractProps: MintingContractProps): Promise<nftData> => {
try {
const tokenInfo = await readContract({
address: `0x${contractProps.address}`,
Expand All @@ -35,118 +36,134 @@ export const getIpfsData = async (tokenId: number, contractProps: MintingContrac

const [, tokenURI] = tokenInfo as [string, string];
const tokenCID = tokenURI.replace("ipfs://", "");

const response = await getDataFromGateways(tokenCID);

const metaData = {
name: response.data.name,
description: response.data.description,
image: response.data.image,
tokenId: tokenId,
}
;
};

return metaData;

return metaData
} catch (error) {
console.error(error);
throw error; // You can choose to rethrow the error or handle it here
}
};


export const useParseIpfsData = (tokenId: number, contractProps: MintingContractProps) => {
const debouncedContractProps = useDebounce(contractProps, 500);
const [ipfsData, setIpfsData] = useState({
name: 'Loading...',
description: 'Loading...',
});
const {data: tokenInfo, isSuccess: isTokenInfoSuccess, isError: isTokenInfoError, error: tokenInfoError } = useContractRead({
address: `0x${debouncedContractProps.address}`,
abi: MintingContractJSON.abi,
functionName: 'getTokenInfo',
args: [tokenId],
chainId: debouncedContractProps.chainId
});
const retrieveIpfsData = useCallback(async () => {
if (isTokenInfoSuccess && tokenInfo) {
const [, tokenURI] = tokenInfo as [string, string]
const tokenCID = tokenURI.replace("ipfs://", "");
try {
const response = await getDataFromGateways(tokenCID);
const metaData = {
name: response.data.name,
description: response.data.description,
image: response.data.image,
};
setIpfsData(metaData);
} catch (error) {
console.error(error);
}
} else if (isTokenInfoError) {
console.log(tokenInfoError)
}
}, [isTokenInfoSuccess, isTokenInfoError, tokenInfo]);

// export const useParseIpfsData = (tokenId: number, contractProps: MintingContractProps) => {
// const debouncedContractProps = useDebounce(contractProps, 500);
// const [ipfsData, setIpfsData] = useState({
// name: 'Loading...',
// description: 'Loading...',
// });
// const {data: tokenInfo, isSuccess: isTokenInfoSuccess, isError: isTokenInfoError, error: tokenInfoError } = useContractRead({
// address: `0x${debouncedContractProps.address}`,
// abi: MintingContractJSON.abi,
// functionName: 'getTokenInfo',
// args: [tokenId],
// chainId: debouncedContractProps.chainId
// });
// const retrieveIpfsData = useCallback(async () => {
// if (isTokenInfoSuccess && tokenInfo) {
// const [, tokenURI] = tokenInfo as [string, string]
// const tokenCID = tokenURI.replace("ipfs://", "");
// try {
// const response = await getDataFromGateways(tokenCID);
// const metaData = {
// name: response.data.name,
// description: response.data.description,
// image: response.data.image,
// };
// setIpfsData(metaData);
// } catch (error) {
// console.error(error);
// }
// } else if (isTokenInfoError) {
// console.log(tokenInfoError)
// }
// }, [isTokenInfoSuccess, isTokenInfoError, tokenInfo]);

useEffect(() => {
retrieveIpfsData();
}, [retrieveIpfsData]);
// useEffect(() => {
// retrieveIpfsData();
// }, [retrieveIpfsData]);

return ipfsData;
};


export const useParseIpfsImage = (tokenId: number, contractProps: MintingContractProps) => {
const debouncedContractProps = useDebounce(contractProps, 500);
const [ipfsImage, setIpfsImage] = useState('');
const {data: tokenInfo, isSuccess: isTokenInfoSuccess, isError: isTokenInfoError, error: tokenInfoError } = useContractRead({
address: `0x${debouncedContractProps.address}`,
abi: MintingContractJSON.abi,
functionName: 'getTokenInfo',
args: [tokenId],
chainId: debouncedContractProps.chainId
});


// const IPFS_GATEWAYS = process.env.IPFS_GATEWAYS!.split(',');

// return ipfsData;
// };

const getImageFromGateways = async (cid: string, gateways: string[]) => {
for (const gateway of gateways) {
try {
const response = await axios.get(`${gateway}/${cid}`, { responseType: 'arraybuffer' }, { timeout: 5000 });
return response;
} catch (error) {
console.error(`Failed to fetch from ${gateway}`, error);
}
export const getIpfsImage = async (ipfsHash: string) => {
const tokenCID = ipfsHash.replace("ipfs://", "");
let imageResponse: any
for (const gateway of ipfsGateways) {
try {
const response = await axios.get(`${gateway}/${tokenCID}`, { responseType: 'arraybuffer' }, { timeout: 5000 });
imageResponse = await response;
const imageBuffer = Buffer.from(imageResponse.data, 'binary');
const imageSrc = 'data:image/jpeg;base64,' + imageBuffer.toString('base64');
return imageSrc
} catch (error) {
console.error(`Failed to fetch from ${gateway}`, error);
}
throw new Error(`Failed to fetch data from all gateways for CID: ${cid}`);
}
};

const retrieveIpfsData = useCallback(async () => {
if (isTokenInfoSuccess && tokenInfo) {
const [, tokenURI] = tokenInfo as [string, string]
const tokenCID = tokenURI.replace("ipfs://", "");
try {
const response = await getDataFromGateways(tokenCID);
const imgHash = response.data.image.replace("ipfs://", "");
const imageResponse = await getImageFromGateways(imgHash, ipfsGateways);
const imageBuffer = Buffer.from(imageResponse.data, 'binary');
const imageSrc = 'data:image/jpeg;base64,' + imageBuffer.toString('base64');
setIpfsImage(imageSrc);
} catch (error) {
console.error(error);
}
} else if (isTokenInfoError) {
console.log(tokenInfoError)
}
}, [ipfsGateways, isTokenInfoSuccess, isTokenInfoError]);

useEffect(() => {
retrieveIpfsData();
}, [retrieveIpfsData]);

return ipfsImage;
};
// export const useParseIpfsImage = (tokenId: number, contractProps: MintingContractProps) => {
// const debouncedContractProps = useDebounce(contractProps, 200);
// const [ipfsImage, setIpfsImage] = useState('');
// const {data: tokenInfo, isSuccess: isTokenInfoSuccess, isError: isTokenInfoError, error: tokenInfoError } = useContractRead({
// address: `0x${debouncedContractProps.address}`,
// abi: MintingContractJSON.abi,
// functionName: 'getTokenInfo',
// args: [tokenId],
// chainId: debouncedContractProps.chainId
// });


// // const IPFS_GATEWAYS = process.env.IPFS_GATEWAYS!.split(',');


// const getImageFromGateways = async (cid: string, gateways: string[]) => {
// for (const gateway of gateways) {
// try {
// const response = await axios.get(`${gateway}/${cid}`, { responseType: 'arraybuffer' }, { timeout: 5000 });
// return response;
// } catch (error) {
// console.error(`Failed to fetch from ${gateway}`, error);
// }
// }
// throw new Error(`Failed to fetch data from all gateways for CID: ${cid}`);
// };

// const retrieveIpfsData = useCallback(async () => {
// if (isTokenInfoSuccess && tokenInfo) {
// const [, tokenURI] = tokenInfo as [string, string]
// const tokenCID = tokenURI.replace("ipfs://", "");
// try {
// const response = await getDataFromGateways(tokenCID);
// const imgHash = response.data.image.replace("ipfs://", "");
// const imageResponse = await getImageFromGateways(imgHash, ipfsGateways);
// const imageBuffer = Buffer.from(imageResponse.data, 'binary');
// const imageSrc = 'data:image/jpeg;base64,' + imageBuffer.toString('base64');
// setIpfsImage(imageSrc);
// } catch (error) {
// console.error(error);
// }
// } else if (isTokenInfoError) {
// console.log(tokenInfoError)
// }
// }, [ipfsGateways, isTokenInfoSuccess, isTokenInfoError]);

// useEffect(() => {
// retrieveIpfsData();
// }, [retrieveIpfsData]);

// return ipfsImage;
// };



Expand Down
Loading

1 comment on commit af91f36

@vercel
Copy link

@vercel vercel bot commented on af91f36 Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.