Skip to content

Commit bff9274

Browse files
committed
token gated content
1 parent 155a631 commit bff9274

File tree

15 files changed

+157
-202
lines changed

15 files changed

+157
-202
lines changed

packages/ui/button/button.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export type ButtonVariant =
1717
| 'black'
1818
| 'white'
1919
| 'pink'
20+
2021
/**
2122
* All the component types allowed by the Button component.
2223
*/

packages/ui/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vercel/examples-ui",
3-
"version": "0.2.7-beta.1",
3+
"version": "0.2.7-beta.2",
44
"main": "index.tsx",
55
"license": "MIT",
66
"scripts": {},

solutions/token-gated-content/README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
# token-gated-content example
22

3-
This example shows how how to created gated token content with Next.js
3+
This example shows how how to created gated token content with Next.js. It contains a sample NFT smart contract to get you started.
44

55
## Demo
66

77
https://token-gated-content.vercel.app
88

99
## How to Use
1010

11+
This example requires you to deploy a smart contract to the Rinkeby ethereum test network:
12+
13+
1. Ensure your Metamask wallet is set to use Rinkeby like [explained here](https://gist.github.com/tschubotz/8047d13a2d2ac8b2a9faa3a74970c7ef).
14+
2. Grab your `address` in metamask and paste it in use it as the `PUBLIC_KEY` env var.![Metamask address](./address.png)
15+
3. In Metamask click the 3 dots icon -> `account details` -> `export private key` and export your key to add it to `PRIVATE_KEY` **If using Mainnet, secure this properly! It can be used to access your wallet**.
16+
![Metamask private key](./private.png)
17+
4. Deploy your own version of the [smart contract](./contract/vercel.sol) to the Rinkeby network and grab the smart contract address to add it to `CONTRACT_ADDRESS` env variable. See this [tutorial](https://medium.com/quick-programming/how-to-deploy-a-smart-contract-using-remix-9e270b253249) on how to deploy smart contracts.
18+
5. Give your application a proper name and add it to `NEXT_PUBLIC_APP_NAME` env var.
19+
20+
Then proceed to deploy as usual to Vercel.
21+
1122
You can choose from one of the following two methods to use this repository:
1223

1324
### One-Click Deploy
118 KB
Loading
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { useUserState } from '../hooks/useUser'
2+
3+
import { CheckIcon } from '@heroicons/react/outline'
4+
import { Text, Link, Button, LoadingDots } from '@vercel/examples-ui'
5+
6+
export const features = [
7+
'Exclusive merchandise content',
8+
'Events and conferences',
9+
'First access to new feature releases',
10+
]
11+
12+
export const Info = () => {
13+
const { handleDisconnect, loading, userState, handleConnect } = useUserState()
14+
15+
const handleLogin = () => {
16+
handleConnect()
17+
}
18+
19+
const noMetamask = userState === 'noMetamask'
20+
const showConnect = userState !== 'noMetamask' && userState !== 'connected'
21+
const showDisconnect = userState === 'connected'
22+
23+
return (
24+
<section className="flex flex-col flex-2 w-full gap-4 text-white">
25+
<div className="relative p-6 bg-dark-accents-0 bg-clip-padding backdrop-filter backdrop-blur-sm bg-opacity-10 rounded-2xl shadow-sm flex flex-col ">
26+
<div className="flex-1">
27+
<Text variant="h1" className="text-white">
28+
Token Gated Content example
29+
</Text>
30+
<Text className="text-white mt-6">
31+
This example shows how you can create Token Gated Content using
32+
Next.js.{' '}
33+
<Link
34+
href="https://github.com/tmm/wagmi"
35+
target="_blank"
36+
className="text-highlight-pink hover:text-highlight-magenta"
37+
>
38+
Wagmi
39+
</Link>{' '}
40+
is used to connect to different wallets and{' '}
41+
<Link
42+
className="text-highlight-pink hover:text-highlight-magenta"
43+
href="https://docs.ethers.io/v5/"
44+
target="_blank"
45+
>
46+
Ethers
47+
</Link>{' '}
48+
is used to interact with the blockchain.
49+
</Text>
50+
<div className="mt-10 p-4 rounded bg-gradient-to-r from-dark-accents-2 via-dark-accents-1 to-transparent">
51+
<Text variant="h2" className="text-2xl text-gray-400">
52+
Member access
53+
</Text>
54+
<Text className="mt-4 text-white">
55+
You can create exclusive areas of you website and ensure only
56+
people owning your token have access to it.
57+
</Text>
58+
<Text className="mt-6">Examples:</Text>
59+
<ul role="list" className="space-y-6">
60+
{features.map((feature) => (
61+
<li key={feature} className="flex mt-2">
62+
<CheckIcon
63+
className="flex-shrink-0 w-6 h-6 text-white"
64+
aria-hidden="true"
65+
/>
66+
<span className="ml-3 text-white">{feature}</span>
67+
</li>
68+
))}
69+
</ul>
70+
71+
<div className="fw-full mt-6 border-t border-dark-accents-4 ">
72+
{noMetamask && (
73+
<Link
74+
href="https://metamask.io/"
75+
target="_blank"
76+
className="text-highlight-pink hover:text-highlight-magenta mt-4"
77+
>
78+
Install metamask to use this example →
79+
</Link>
80+
)}
81+
82+
{showDisconnect && (
83+
<Button
84+
variant="ghost"
85+
onClick={handleDisconnect}
86+
className="text-highlight-pink hover:text-highlight-magenta mt-4"
87+
>
88+
{loading ? <LoadingDots /> : 'Disconnect your wallets →'}
89+
</Button>
90+
)}
91+
92+
{showConnect && (
93+
<Button
94+
variant="ghost"
95+
onClick={handleLogin}
96+
className="text-highlight-pink hover:text-highlight-magenta mt-4"
97+
>
98+
{loading ? <LoadingDots /> : 'Connect your wallets →'}
99+
</Button>
100+
)}
101+
</div>
102+
</div>
103+
</div>
104+
</div>
105+
</section>
106+
)
107+
}

solutions/token-gated-content/components/ProductCard.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,19 @@ export function ProductCard({ product, blur }: Props) {
2727
setLoading(false)
2828
}, 750)
2929
}
30+
3031
return (
3132
<div className="bg-dark-accents-0">
3233
<div className="relative">
33-
<div className="relative w-full rounded-lg overflow-hidden">
34+
<div className="w-full flex justify-center rounded-lg overflow-hidden">
3435
<Image
3536
className={`pointer-events-none w-full h-full object-center object-cover ${
3637
blur ? 'blur' : ''
3738
}`}
3839
alt={product.title}
3940
src={product.image}
40-
width="2248"
41-
height="1686"
41+
width="500"
42+
height="500"
4243
/>
4344
</div>
4445
<div className="absolute top-0 inset-x-0 rounded-lg p-4 flex items-end justify-end overflow-hidden">

solutions/token-gated-content/hooks/useUser.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ export const useUserState = (route?: string) => {
7575

7676
// if we're on the right network, we need to check if we're signed
7777
if (data?.address && networkData.chain?.name === 'Rinkeby') {
78+
const localData = localStorage.getItem('userApproval')
79+
if (localData) {
80+
const signedWith = utils.verifyMessage(
81+
`I approve connecting to ${process.env.NEXT_PUBLIC_APP_NAME}`,
82+
localData
83+
)
84+
85+
if (signedWith === data?.address) {
86+
setSignature(localData)
87+
return
88+
}
89+
}
7890
setState('signature')
7991
return
8092
}

solutions/token-gated-content/package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

solutions/token-gated-content/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"dependencies": {
1313
"@heroicons/react": "^1.0.6",
1414
"@tsndr/cloudflare-worker-jwt": "^1.1.6",
15-
"@vercel/examples-ui": "^0.2.7-beta.0",
15+
"@vercel/examples-ui": "^0.2.7-beta.2",
1616
"ethers": "^5.6.0",
1717
"heroicons": "^1.0.6",
1818
"jsonwebtoken": "^8.5.1",

0 commit comments

Comments
 (0)