Skip to content

Commit 963ad2c

Browse files
committed
feat: GridItem & buyToken states
1 parent 9a51077 commit 963ad2c

14 files changed

+233
-115
lines changed

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

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export type LarskristoHellheadsContextControllerProps = {
88

99
export type LarskristoHellheadsContextActions = {
1010
fetchContractValues: { isLoading: boolean };
11+
buyToken: { isPending: boolean; isConfirmed: boolean; transactionHash?: string };
1112
};
1213

1314
export type LarskristoHellheadsContractValues = {

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

+24-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useEffect, useState } from "react";
22
import { Client, getContract } from "viem";
3-
import { useAccount, useWriteContract } from "wagmi";
3+
import { useAccount, useWaitForTransactionReceipt, useWriteContract } from "wagmi";
44
import { getClient } from "@wagmi/core";
55
import { ethers } from "ethers";
66

@@ -32,11 +32,33 @@ export const LarskristoHellheadsContextController = ({ children }: LarskristoHel
3232
fetchContractValues: {
3333
isLoading: false,
3434
},
35+
buyToken: {
36+
isPending: false,
37+
isConfirmed: false,
38+
},
3539
});
3640

3741
const { address: connectedAccountAddress, chainId } = useAccount();
3842
const { wagmiConfig } = useEvmWalletSelectorContext();
39-
const { error: writeContractError, writeContract } = useWriteContract();
43+
const { data: hash, error: writeContractError, writeContract, isPending } = useWriteContract();
44+
const {
45+
isLoading: isConfirming,
46+
isSuccess: isConfirmed,
47+
data,
48+
} = useWaitForTransactionReceipt({
49+
hash,
50+
});
51+
52+
useEffect(() => {
53+
setActions((prev) => ({
54+
...prev,
55+
buyToken: {
56+
isPending: isPending || isConfirming,
57+
isConfirmed,
58+
transactionHash: data?.transactionHash,
59+
},
60+
}));
61+
}, [isPending, isConfirming, isConfirmed, data]);
4062

4163
if (writeContractError) {
4264
console.error(writeContractError);

app/src/providers/evm/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import client from "./client";
22

3+
const getBlockExplorerUrl = () =>
4+
process.env.NEXT_PUBLIC_DEFAULT_NETWORK_ENV === "testnet" ? "https://sepolia.etherscan.io" : "https://etherscan.io";
5+
36
export default {
47
client,
8+
getBlockExplorerUrl,
59
};

app/src/ui/svpervnder/collections/larskristo_hellheads/LarsKristoHellheads.module.scss

-59
Original file line numberDiff line numberDiff line change
@@ -15,63 +15,4 @@
1515
&__grid {
1616
margin-top: $space-l;
1717
}
18-
19-
&__item {
20-
display: block;
21-
margin-bottom: $space-default;
22-
23-
&:hover {
24-
[class*="icon-"] {
25-
color: var(--color-primary);
26-
transform: scale(1.5);
27-
transition: transform 0.1s ease-in-out;
28-
}
29-
}
30-
31-
[class*="icon-"] {
32-
transition: transform 0.1s ease-in-out;
33-
}
34-
35-
&--img {
36-
padding: $space-xs;
37-
38-
img {
39-
width: 100%;
40-
}
41-
}
42-
43-
&--name-row {
44-
display: flex;
45-
justify-content: space-between;
46-
}
47-
48-
&--price-row {
49-
display: flex;
50-
justify-content: space-between;
51-
52-
> div {
53-
display: flex;
54-
flex-direction: column;
55-
justify-content: center;
56-
align-items: center;
57-
}
58-
}
59-
60-
&--price {
61-
color: var(--color-typography-text);
62-
63-
span {
64-
color: var(--color-typography-description);
65-
}
66-
}
67-
68-
&--expand {
69-
font-size: $font-size-text;
70-
color: var(--color-typography-description);
71-
72-
&:hover {
73-
cursor: pointer;
74-
}
75-
}
76-
}
7718
}

app/src/ui/svpervnder/collections/larskristo_hellheads/LarsKristoHellheads.module.scss.d.ts

-6
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ export type Styles = {
33
"latest-collection__grid": string;
44
"latest-collection__intro": string;
55
"latest-collection__intro--artist-name": string;
6-
"latest-collection__item": string;
7-
"latest-collection__item--expand": string;
8-
"latest-collection__item--img": string;
9-
"latest-collection__item--name-row": string;
10-
"latest-collection__item--price": string;
11-
"latest-collection__item--price-row": string;
126
"z-depth-0": string;
137
"z-depth-1": string;
148
"z-depth-1-half": string;

app/src/ui/svpervnder/collections/larskristo_hellheads/LarsKristoHellheads.tsx

+2-30
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ import { useState } from "react";
44
import { Grid } from "ui/grid/Grid";
55
import { Typography } from "ui/typography/Typography";
66
import { Button } from "ui/button/Button";
7-
import { Card } from "ui/card/Card";
8-
import { Icon } from "ui/icon/Icon";
97

108
import styles from "./LarsKristoHellheads.module.scss";
119
import { ItemMetadata, LatestCollectionProps } from "./LarsKristoHellheads.types";
1210
import metadata from "./metadata.json";
1311
import { DetailsModal } from "./details-modal/DetailsModal";
12+
import { GridItem } from "./grid-item/GridItem";
1413

1514
export const LarsKristoHellheads: React.FC<LatestCollectionProps> = ({ className }) => {
1615
const [isDetailsModalVisible, displayDetailsModals] = useState(false);
@@ -59,34 +58,7 @@ export const LarsKristoHellheads: React.FC<LatestCollectionProps> = ({ className
5958
<section className={styles["latest-collection__grid"]}>
6059
<Grid.Row>
6160
{metadata.map((item: ItemMetadata, index) => (
62-
<Grid.Col lg={3} xs={6} key={item.thumbnail}>
63-
<Card className={styles["latest-collection__item"]} withSpotlightEffect>
64-
<div className={styles["latest-collection__item--img"]}>
65-
<img src={item.thumbnail} alt={item.name} />
66-
</div>
67-
<Card.Content>
68-
<div className={styles["latest-collection__item--name-row"]}>
69-
<div>
70-
<Typography.Description>{item.name}</Typography.Description>
71-
</div>
72-
</div>
73-
<div className={styles["latest-collection__item--price-row"]}>
74-
<div>
75-
<Typography.TextLead flat className={styles["latest-collection__item--price"]}>
76-
1.75 <span>ETH</span>
77-
</Typography.TextLead>
78-
</div>
79-
<div>
80-
<Icon
81-
name="icon-expand"
82-
className={styles["latest-collection__item--expand"]}
83-
onClick={() => handleExpand(item, index)}
84-
/>
85-
</div>
86-
</div>
87-
</Card.Content>
88-
</Card>
89-
</Grid.Col>
61+
<GridItem key={item.thumbnail} item={item} index={index} handleExpand={handleExpand} />
9062
))}
9163
</Grid.Row>
9264
</section>

app/src/ui/svpervnder/collections/larskristo_hellheads/details-modal/DetailsModal.module.scss

+7
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@
4343
display: flex;
4444
justify-content: space-between;
4545

46+
&--success {
47+
margin-top: $space-default;
48+
padding: $space-default;
49+
color: var(--color-background);
50+
background-color: var(--color-primary-shade-low);
51+
}
52+
4653
&--connect-wallet {
4754
margin-bottom: $space-default;
4855
}

app/src/ui/svpervnder/collections/larskristo_hellheads/details-modal/DetailsModal.module.scss.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type Styles = {
1010
"details-modal__price-block--connect-wallet": string;
1111
"details-modal__price-block--owner-pill": string;
1212
"details-modal__price-block--price": string;
13+
"details-modal__price-block--success": string;
1314
"details-modal__price-card": string;
1415
"z-depth-0": string;
1516
"z-depth-1": string;

app/src/ui/svpervnder/collections/larskristo_hellheads/details-modal/DetailsModal.tsx

+37-18
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ import { Card } from "ui/card/Card";
1010
import { Button } from "ui/button/Button";
1111
import { useLarskristoHellheadsContext } from "context/evm/larskristo-hellheads/useLarskristoHellheadsContext";
1212
import { Icon } from "ui/icon/Icon";
13+
import evm from "providers/evm";
1314

1415
import { DetailsModalProps } from "./DetailsModal.types";
1516
import styles from "./DetailsModal.module.scss";
1617

1718
export const DetailsModal: React.FC<DetailsModalProps> = ({ onClose, className, item }) => {
18-
const larskristohellheads = useLarskristoHellheadsContext();
19-
const { data: ensName } = useEnsName({ address: larskristohellheads.owner });
19+
const ERC721 = useLarskristoHellheadsContext();
20+
const { data: ensName } = useEnsName({ address: ERC721.owner });
2021
const { open } = useWeb3Modal();
2122
const { isConnected } = useAccount();
2223

@@ -29,23 +30,23 @@ export const DetailsModal: React.FC<DetailsModalProps> = ({ onClose, className,
2930
};
3031

3132
const handleOnBuyNowClick = () => {
32-
larskristohellheads.buyToken(item.id!);
33+
ERC721.buyToken(item.id!);
3334
};
3435

3536
useEffect(() => {
3637
(async () => {
37-
await larskristohellheads.ownerOf(item.id!);
38-
await larskristohellheads.getTokenPrice(item.id!);
38+
await ERC721.ownerOf(item.id!);
39+
await ERC721.getTokenPrice(item.id!);
3940
})();
4041
}, [item.id]);
4142

4243
useEffect(() => {
43-
if (!larskristohellheads.tokenPrice?.rawValue) return;
44+
if (!ERC721.tokenPrice?.rawValue) return;
4445

4546
(async () => {
46-
await larskristohellheads.royaltyInfo(item.id!);
47+
await ERC721.royaltyInfo(item.id!);
4748
})();
48-
}, [larskristohellheads.tokenPrice?.rawValue]);
49+
}, [ERC721.tokenPrice?.rawValue]);
4950

5051
return (
5152
<Modal
@@ -68,7 +69,7 @@ export const DetailsModal: React.FC<DetailsModalProps> = ({ onClose, className,
6869
</div>
6970
</div>
7071
<Typography.TextLead flat>
71-
{larskristohellheads.contractValues?.name}, {larskristohellheads.contractValues?.symbol}
72+
{ERC721.contractValues?.name}, {ERC721.contractValues?.symbol}
7273
</Typography.TextLead>
7374
</Modal.Header>
7475
<Modal.Content>
@@ -88,14 +89,13 @@ export const DetailsModal: React.FC<DetailsModalProps> = ({ onClose, className,
8889
<div>
8990
<Typography.Headline5 flat>Price</Typography.Headline5>
9091
<Typography.Headline4 className={styles["details-modal__price-block--price"]}>
91-
{larskristohellheads.tokenPrice?.formattedValue}{" "}
92-
<span>ETH | {larskristohellheads.tokenPrice?.exchangeRateFormatted}</span>
92+
{ERC721.tokenPrice?.formattedValue}{" "}
93+
<span>ETH | {ERC721.tokenPrice?.exchangeRateFormatted}</span>
9394
</Typography.Headline4>
9495
</div>
9596
<div>
9697
<Typography.Text flat truncate className={styles["details-modal__price-block--owner-pill"]}>
97-
<span>Owned by:</span>{" "}
98-
<Typography.Anchor>{ensName || larskristohellheads.owner}</Typography.Anchor>
98+
<span>Owned by:</span> <Typography.Anchor>{ensName || ERC721.owner}</Typography.Anchor>
9999
</Typography.Text>
100100
</div>
101101
</div>
@@ -107,10 +107,29 @@ export const DetailsModal: React.FC<DetailsModalProps> = ({ onClose, className,
107107
</div>
108108
)}
109109
<div className={styles["details-modal__price-block--buy-now"]}>
110-
<Button fullWidth disabled={!isConnected} onClick={handleOnBuyNowClick}>
111-
Buy for: {larskristohellheads.tokenPrice?.formattedValue} ETH
110+
<Button
111+
fullWidth
112+
disabled={!isConnected || ERC721.actions.buyToken.isPending}
113+
onClick={handleOnBuyNowClick}
114+
isLoading={ERC721.actions.buyToken.isPending}
115+
>
116+
Buy for: {ERC721.tokenPrice?.formattedValue} ETH
112117
</Button>
113118
</div>
119+
{ERC721.actions.buyToken.isConfirmed && (
120+
<div className={styles["details-modal__price-block--success"]}>
121+
{ERC721.actions.buyToken.isConfirmed && (
122+
<Typography.Text flat>
123+
Purchase confirmed! Check your transaction{" "}
124+
<Typography.Anchor
125+
href={`${evm.getBlockExplorerUrl()}/tx/${ERC721.actions.buyToken.transactionHash}`}
126+
>
127+
here <Icon name="icon-exit-up2" />
128+
</Typography.Anchor>
129+
</Typography.Text>
130+
)}
131+
</div>
132+
)}
114133
</Card.Content>
115134
</Card>
116135
<Card className={styles["details-modal__author-card"]}>
@@ -145,7 +164,7 @@ export const DetailsModal: React.FC<DetailsModalProps> = ({ onClose, className,
145164
<Typography.Headline5>Details</Typography.Headline5>
146165
<div className={styles["details-modal__details-card--row"]}>
147166
<Typography.Text flat>Contract Address</Typography.Text>
148-
<Typography.Anchor truncate>{larskristohellheads.contractAddress}</Typography.Anchor>
167+
<Typography.Anchor truncate>{ERC721.contractAddress}</Typography.Anchor>
149168
</div>
150169
<div className={styles["details-modal__details-card--row"]}>
151170
<Typography.Text flat>Token ID</Typography.Text>
@@ -157,11 +176,11 @@ export const DetailsModal: React.FC<DetailsModalProps> = ({ onClose, className,
157176
</div>
158177
<div className={styles["details-modal__details-card--row"]}>
159178
<Typography.Text flat>Owner</Typography.Text>
160-
<Typography.Anchor truncate>{ensName || larskristohellheads.owner}</Typography.Anchor>
179+
<Typography.Anchor truncate>{ensName || ERC721.owner}</Typography.Anchor>
161180
</div>
162181
<div className={styles["details-modal__details-card--row"]}>
163182
<Typography.Text flat>Royalty</Typography.Text>
164-
<Typography.Anchor>{larskristohellheads.royalty?.percentageFormatted}</Typography.Anchor>
183+
<Typography.Anchor>{ERC721.royalty?.percentageFormatted}</Typography.Anchor>
165184
</div>
166185
<div className={styles["details-modal__details-card--row"]}>
167186
<Typography.Text flat>Chain</Typography.Text>

0 commit comments

Comments
 (0)