Skip to content

Commit d4530ac

Browse files
committed
feat: token page WIP
1 parent 7168630 commit d4530ac

33 files changed

+714
-638
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { createContext } from "react";
2+
3+
import { ERC721ContextType } from "./ERC721Context.types";
4+
5+
export const ERC721Context = createContext<ERC721ContextType | undefined>(undefined);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { ReactNode } from "react";
2+
3+
import { ZeroXAddress } from "../wallet-selector/EvmWalletSelectorContext.types";
4+
5+
export type ItemMetadata = {
6+
id?: number;
7+
name: string;
8+
description: string;
9+
image: string;
10+
thumbnail: string;
11+
};
12+
13+
export type ERC721ContextControllerProps = {
14+
children: ReactNode;
15+
address: ZeroXAddress;
16+
tokenId: ZeroXAddress;
17+
};
18+
19+
export type ERC721ContextActions = {
20+
fetchContractValues: { isLoading: boolean };
21+
getTokenPrice: { isLoading: boolean };
22+
buyToken: { isPending: boolean; isConfirmed: boolean; transactionHash?: string };
23+
};
24+
25+
export type ERC721ContractValues = {
26+
name: string;
27+
symbol: string;
28+
};
29+
30+
export type TokenPrice = {
31+
rawValue: bigint;
32+
formattedValue: string;
33+
exchangeRate?: number;
34+
exchangeRateFormatted?: string;
35+
};
36+
37+
export type Royalty = {
38+
rawValue: bigint;
39+
percentage: number;
40+
percentageFormatted: string;
41+
};
42+
43+
export type ERC721ContextType = {
44+
contractValues?: ERC721ContractValues;
45+
contractAddress?: string;
46+
actions: ERC721ContextActions;
47+
owner?: ZeroXAddress;
48+
tokenPrice?: TokenPrice;
49+
tokenMetadata?: ItemMetadata;
50+
royalty?: Royalty;
51+
fetchContractValues: () => Promise<void>;
52+
ownerOf: () => Promise<void>;
53+
getTokenPrice: (options?: { excludeExchangeRate?: boolean }) => Promise<TokenPrice | undefined>;
54+
royaltyInfo: () => Promise<void>;
55+
buyToken: () => Promise<void>;
56+
getTokenUri: () => Promise<void>;
57+
getTokenMetadata: () => Promise<void>;
58+
connectedAccountIsOwner: () => boolean;
59+
};

app/src/context/evm/larskristo-hellheads/LarskristoHellheadsContextController.tsx app/src/context/evm/larskristo-hellheads/ERC721ContextController.tsx

+85-48
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,36 @@ import React, { useEffect, useState } from "react";
22
import { getContract } from "viem";
33
import { useAccount } from "wagmi";
44
import { ethers } from "ethers";
5+
import axios from "axios";
56

67
import { LarsKristoHellheads__factory } from "providers/evm/contracts/larskristohellheads/LarsKristoHellheads__factory";
78
import currency from "providers/currency";
89
import { ZeroXAddress } from "../wallet-selector/EvmWalletSelectorContext.types";
910
import evm from "providers/evm";
1011

11-
import { LarskristoHellheadsContext } from "./LarskristoHellheadsContext";
12+
import { ERC721Context } from "./ERC721Context";
1213
import {
13-
LarskristoHellheadsContextActions,
14-
LarskristoHellheadsContextControllerProps,
15-
LarskristoHellheadsContextType,
16-
LarskristoHellheadsContractValues,
14+
ERC721ContextActions,
15+
ERC721ContextControllerProps,
16+
ERC721ContextType,
17+
ERC721ContractValues,
18+
ItemMetadata,
1719
Royalty,
1820
TokenPrice,
19-
} from "./LarskristoHellheadsContext.types";
20-
21-
const SEPOLIA_TESTNET_ADDRESS = "0x2abbf9c29606b4c752944942aa9952ac2cdf552b";
22-
const ETHEREUM_MAINNET_ADDRESS = "0x5D003EBE7348d6D3aC1a397619ED2016711d7615";
23-
24-
export const LarskristoHellheadsContextController = ({ children }: LarskristoHellheadsContextControllerProps) => {
25-
const [contractAddress, setContractAddress] = useState<string | undefined>();
26-
const [contractValues, setContractValues] = useState<LarskristoHellheadsContractValues>();
21+
} from "./ERC721Context.types";
22+
23+
export const ERC721ContextController = ({
24+
children,
25+
tokenId,
26+
address: contractAddress,
27+
}: ERC721ContextControllerProps) => {
28+
const [contractValues, setContractValues] = useState<ERC721ContractValues>();
2729
const [owner, setOwner] = useState<`0x${string}`>();
2830
const [tokenPrice, setTokenPrice] = useState<TokenPrice | undefined>();
2931
const [royalty, setRoyaltyInfo] = useState<Royalty | undefined>();
30-
const [actions, setActions] = useState<LarskristoHellheadsContextActions>({
32+
const [tokenUri, setTokenUri] = useState<string | undefined>();
33+
const [tokenMetadata, setTokenMetadata] = useState<ItemMetadata | undefined>();
34+
const [actions, setActions] = useState<ERC721ContextActions>({
3135
fetchContractValues: {
3236
isLoading: false,
3337
},
@@ -52,7 +56,7 @@ export const LarskristoHellheadsContextController = ({ children }: LarskristoHel
5256

5357
const connectedAccountIsOwner = () => owner === connectedAccountAddress;
5458

55-
const buyToken = async (tokenId: number) => {
59+
const buyToken = async () => {
5660
try {
5761
setActions((prev) => ({
5862
...prev,
@@ -89,7 +93,53 @@ export const LarskristoHellheadsContextController = ({ children }: LarskristoHel
8993
}
9094
};
9195

92-
const getTokenPrice = async (tokenId: number, options?: { excludeExchangeRate?: boolean }) => {
96+
const getTokenMetadata = async () => {
97+
try {
98+
const result = await axios.get(tokenUri!, {
99+
headers: {
100+
"Content-Type": "application/json",
101+
},
102+
});
103+
104+
setTokenMetadata({
105+
...result.data,
106+
id: tokenId,
107+
});
108+
} catch (error) {
109+
console.error(error);
110+
}
111+
};
112+
113+
const getTokenUri = async () => {
114+
try {
115+
const contract = getContractInstance();
116+
117+
const result = await contract.read.tokenURI([BigInt(tokenId)]);
118+
119+
setTokenUri(result);
120+
} catch (error) {
121+
console.error(error);
122+
}
123+
};
124+
125+
const royaltyInfo = async () => {
126+
try {
127+
const contract = getContractInstance();
128+
129+
const [, rawValue] = await contract.read.royaltyInfo([BigInt(tokenId), tokenPrice!.rawValue]);
130+
const percentage = Number(ethers.formatEther(rawValue)) / Number(ethers.formatEther(tokenPrice!.rawValue));
131+
132+
setRoyaltyInfo({
133+
rawValue,
134+
percentage,
135+
percentageFormatted: `${(percentage * 100).toFixed(2)}%`,
136+
});
137+
} catch (error) {
138+
console.error(error);
139+
}
140+
};
141+
142+
const getTokenPrice = async (options?: { excludeExchangeRate?: boolean }) => {
93143
try {
94144
setActions((prev) => ({
95145
...prev,
@@ -143,24 +193,7 @@ export const LarskristoHellheadsContextController = ({ children }: LarskristoHel
143193
};
144194
};
145195

146-
const royaltyInfo = async (tokenId: number) => {
147-
try {
148-
const contract = getContractInstance();
149-
150-
const [, rawValue] = await contract.read.royaltyInfo([BigInt(tokenId), tokenPrice!.rawValue]);
151-
const percentage = Number(ethers.formatEther(rawValue)) / Number(ethers.formatEther(tokenPrice!.rawValue));
152-
153-
setRoyaltyInfo({
154-
rawValue,
155-
percentage,
156-
percentageFormatted: `${(percentage * 100).toFixed(2)}%`,
157-
});
158-
} catch (error) {
159-
console.error(error);
160-
}
161-
};
162-
163-
const ownerOf = async (tokenId: number) => {
196+
const ownerOf = async () => {
164197
try {
165198
const contract = getContractInstance();
166199

@@ -172,7 +205,7 @@ export const LarskristoHellheadsContextController = ({ children }: LarskristoHel
172205
}
173206
};
174207

175-
const fetchContractValues = async (address: string) => {
208+
const fetchContractValues = async () => {
176209
setActions((prev) => ({
177210
...prev,
178211
fetchContractValues: {
@@ -181,15 +214,11 @@ export const LarskristoHellheadsContextController = ({ children }: LarskristoHel
181214
}));
182215

183216
try {
184-
const contract = getContract({
185-
address: address as ZeroXAddress,
186-
abi: LarsKristoHellheads__factory.abi,
187-
client: publicClient,
188-
});
217+
const contract = getContractInstance();
189218

190219
const [name, symbol] = await Promise.all([contract.read.name(), contract.read.symbol()]);
191220

192-
const values: LarskristoHellheadsContractValues = {
221+
const values: ERC721ContractValues = {
193222
name,
194223
symbol,
195224
};
@@ -208,16 +237,21 @@ export const LarskristoHellheadsContextController = ({ children }: LarskristoHel
208237
};
209238

210239
useEffect(() => {
211-
const address =
212-
process.env.NEXT_PUBLIC_DEFAULT_NETWORK_ENV === "testnet" ? SEPOLIA_TESTNET_ADDRESS : ETHEREUM_MAINNET_ADDRESS;
213-
setContractAddress(address);
214-
215240
(async () => {
216-
await fetchContractValues(address);
241+
await getTokenUri();
242+
await fetchContractValues();
217243
})();
218244
}, []);
219245

220-
const props: LarskristoHellheadsContextType = {
246+
useEffect(() => {
247+
if (!tokenUri) return;
248+
249+
(async () => {
250+
await getTokenMetadata();
251+
})();
252+
}, [tokenUri]);
253+
254+
const props: ERC721ContextType = {
221255
fetchContractValues,
222256
contractValues,
223257
actions,
@@ -230,7 +264,10 @@ export const LarskristoHellheadsContextController = ({ children }: LarskristoHel
230264
royaltyInfo,
231265
royalty,
232266
connectedAccountIsOwner,
267+
getTokenUri,
268+
getTokenMetadata,
269+
tokenMetadata,
233270
};
234271

235-
return <LarskristoHellheadsContext.Provider value={props}>{children}</LarskristoHellheadsContext.Provider>;
272+
return <ERC721Context.Provider value={props}>{children}</ERC721Context.Provider>;
236273
};

app/src/context/evm/larskristo-hellheads/LarskristoHellheadsContext.tsx

-5
This file was deleted.

app/src/context/evm/larskristo-hellheads/LarskristoHellheadsContext.types.ts

-46
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { useContext } from "react";
2+
3+
import { ERC721Context } from "./ERC721Context";
4+
5+
export const useERC721Context = () => {
6+
const context = useContext(ERC721Context);
7+
8+
if (context === undefined) {
9+
throw new Error("useERC721Context must be used within a ERC721Context");
10+
}
11+
12+
return context;
13+
};

app/src/context/evm/larskristo-hellheads/useLarskristoHellheadsContext.tsx

-13
This file was deleted.

app/src/context/theme/ThemeContextController.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import { LocalStorageKeys } from "hooks/useLocalStorage/useLocalStorage.types";
77
import { ThemeContext } from "./ThemeContext";
88
import { ThemeContextControllerProps } from "./ThemeContext.types";
99

10-
const themes: Theme[] = ["svpervnder"];
10+
const themes: Theme[] = ["lease721"];
1111

1212
export const ThemeContextController = ({ children }: ThemeContextControllerProps) => {
13-
const [theme, setTheme] = useState<Theme>("svpervnder");
13+
const [theme, setTheme] = useState<Theme>("lease721");
1414

1515
const localStorage = useLocalStorage();
1616

0 commit comments

Comments
 (0)