From 1e5d847566f3f73b7da81d440a55902554f5411c Mon Sep 17 00:00:00 2001 From: Luc Date: Sat, 27 Jan 2024 20:57:12 +0000 Subject: [PATCH] Introduce POAP Claiming --- app/[slug]/layout.tsx | 1 + app/[slug]/page.tsx | 14 +- app/layout.tsx | 4 +- app/styles/ethdenver24.css | 22 ++ app/styles/frensday.css | 6 + app/styles/generic.css | 9 + components/POAPModal/POAPModal.tsx | 36 +- .../POAPModal/stages/AlreadyClaimed.tsx | 18 + components/POAPModal/stages/ClaimError.tsx | 26 ++ components/POAPModal/stages/Expired.tsx | 2 +- components/POAPModal/stages/MintToProfile.tsx | 33 +- components/POAPModal/stages/NameInput.tsx | 3 - .../POAPModal/stages/PendingApproval.tsx | 2 +- hooks/mintPOAP.ts | 39 ++ hooks/useIYKRef.ts | 4 +- public/ethdenver24/bg.svg | 358 ++++++++++++++++++ 16 files changed, 552 insertions(+), 25 deletions(-) create mode 100644 app/styles/ethdenver24.css create mode 100644 components/POAPModal/stages/AlreadyClaimed.tsx create mode 100644 components/POAPModal/stages/ClaimError.tsx create mode 100644 hooks/mintPOAP.ts create mode 100644 public/ethdenver24/bg.svg diff --git a/app/[slug]/layout.tsx b/app/[slug]/layout.tsx index 0cb396b..beed072 100644 --- a/app/[slug]/layout.tsx +++ b/app/[slug]/layout.tsx @@ -1,4 +1,5 @@ import '../styles/frensday.css'; +import '../styles/ethdenver24.css'; import '../styles/generic.css'; import React from 'react'; diff --git a/app/[slug]/page.tsx b/app/[slug]/page.tsx index c58586b..58f84ff 100644 --- a/app/[slug]/page.tsx +++ b/app/[slug]/page.tsx @@ -15,6 +15,12 @@ import { useWarpcast } from '../../hooks/useWarpcast'; const theme2Class = { frensday2023: 'theme-frensday2023', + ethdenver2024: 'theme-ethdenver24', +}; + +const theme2Color = { + frensday2023: '#2A2244', + ethdenver2024: '#844AFF', }; export default async function ({ @@ -84,7 +90,7 @@ export default async function ({ Site by{' '} ENS @@ -92,7 +98,7 @@ export default async function ({ &{' '} V3X @@ -107,11 +113,14 @@ export default async function ({ export async function generateMetadata({ params: { slug }, + searchParams: { event, iykRef }, }: { params: { slug: string }; + searchParams: { event?: string; iykRef?: string }; }) { const raw_name = slug; const name = ens_normalize(raw_name.toLowerCase()); + const theme_color = theme2Color[event] || '#fff'; if (raw_name.toLowerCase() !== name) { throw new Error('Invalid ENS name'); @@ -124,5 +133,6 @@ export async function generateMetadata({ description: data.records?.description || `View ${data.name}'s ENS Page`, icons: data.avatar, + themeColor: theme_color, } as Metadata; } diff --git a/app/layout.tsx b/app/layout.tsx index 0caaecc..6305e65 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -3,8 +3,8 @@ import './global.css'; import React from 'react'; export const metadata = { - title: 'Next.js', - description: 'Generated by Next.js', + title: 'ENS Page', + description: 'Created with <3', }; export default function RootLayout({ diff --git a/app/styles/ethdenver24.css b/app/styles/ethdenver24.css new file mode 100644 index 0000000..55519af --- /dev/null +++ b/app/styles/ethdenver24.css @@ -0,0 +1,22 @@ +html:has(.theme-ethdenver24) { + body, html { + @apply bg-gradient-to-b from-[#844AFF] to-[#844AFF] text-white; + } + /* body:before { + content: ''; + @apply fixed inset-0 -z-10 brightness-75; + background: url('/ethdenver24/bg.svg') no-repeat center center; + } */ + .btn { + @apply bg-[#FF65AF] hover:bg-[#FF65AF] active:bg-[#FF65AF] text-white; + } + .card-bg { + @apply bg-[#F8F8F9] shadow-lg; + } + .card-body { + @apply text-black; + } + .link { + @apply text-[#FF65AF]; + } +} diff --git a/app/styles/frensday.css b/app/styles/frensday.css index 87106e4..cc16a49 100644 --- a/app/styles/frensday.css +++ b/app/styles/frensday.css @@ -5,4 +5,10 @@ html:has(.theme-frensday2023) { .btn { @apply bg-[#7116EB] hover:bg-[#781dff] active:bg-[#5e0fc8]; } + .card-bg { + @apply bg-[#14032C]; + } + .link { + @apply text-ens-light-blue; + } } diff --git a/app/styles/generic.css b/app/styles/generic.css index b5a7bd5..1f29773 100644 --- a/app/styles/generic.css +++ b/app/styles/generic.css @@ -18,4 +18,13 @@ html:has(.theme-generic) { .btn-url { @apply bg-ens-light-purple-primary hover:bg-ens-light-purple-bright active:bg-ens-light-purple-active; } + .card-bg { + @apply bg-ens-light-background-primary border border-ens-light-border shadow-xl; + } + .card-body { + @apply text-black; + } + .link { + @apply text-ens-light-blue; + } } diff --git a/components/POAPModal/POAPModal.tsx b/components/POAPModal/POAPModal.tsx index a646ca1..4f1f408 100644 --- a/components/POAPModal/POAPModal.tsx +++ b/components/POAPModal/POAPModal.tsx @@ -8,6 +8,7 @@ import { IYKRefResponse as IYKReferenceResponse } from '../../hooks/useIYKRef'; import { POAPMetadata } from '../../hooks/usePOAPData'; import { Creeper } from './Creeper'; import { SHOW_POAP_ANYWAYS } from './settings'; +import { ClaimError } from './stages/ClaimError'; import { ExpiredPOAP } from './stages/Expired'; import { MintToProfile } from './stages/MintToProfile'; import { NameInput } from './stages/NameInput'; @@ -20,6 +21,7 @@ const PENDING_APPROVAL = 'pending-approval'; const MINT_TO = 'mint-to'; const NAME_INPUT = 'name-input'; const EXPIRED_STATE = 'expired'; +const ERROR_STATE = 'error-state'; const event_names = { frensday2023: 'frENSday 2023', @@ -40,6 +42,7 @@ export const POAPModal: FC<{ // eslint-disable-next-line no-undef localStorage?.getItem(STORAGE_NAME_KEY) || '' ); + const [mintToProfileError, setMintToProfileError] = useState(); const [poapEvent] = data.poapEvents; const expiry_data = metadata.attributes.find( @@ -66,27 +69,28 @@ export const POAPModal: FC<{ let state = ''; - if (pendingApproval) { - state = PENDING_APPROVAL; + if (mintToProfileError) { + state = ERROR_STATE; } else { - if (poapEvent.status == 'expired') { - state = EXPIRED_STATE; + if (pendingApproval) { + state = PENDING_APPROVAL; } else { - state = mintToProfile ? MINT_TO : NAME_INPUT; + if (poapEvent.status == 'expired') { + state = EXPIRED_STATE; + } else { + state = mintToProfile ? MINT_TO : NAME_INPUT; + } } } return (
-
+
{event == 'frensday2023' && }
@@ -113,6 +117,7 @@ export const POAPModal: FC<{ poap_name={name} event_name={event_name} address={mintToProfile} + iykData={data} onCallChange={() => { setMintToProfile(''); // eslint-disable-next-line no-undef @@ -121,6 +126,9 @@ export const POAPModal: FC<{ onCallClose={() => { setDismissed(true); }} + onMintToProfileError={(error) => { + setMintToProfileError(error); + }} /> )} {state === NAME_INPUT && ( @@ -138,7 +146,15 @@ export const POAPModal: FC<{ /> )} {state === EXPIRED_STATE && } + {state === ERROR_STATE && ( + + )}
+ {/* {poapEvent.status} */} + {/* {JSON.stringify(data)} */} {/*
Claim your POAP to show you met {name} at frENSday! diff --git a/components/POAPModal/stages/AlreadyClaimed.tsx b/components/POAPModal/stages/AlreadyClaimed.tsx new file mode 100644 index 0000000..3e322f8 --- /dev/null +++ b/components/POAPModal/stages/AlreadyClaimed.tsx @@ -0,0 +1,18 @@ +import { FC } from 'react'; + +export const AlreadyClaimed: FC<{ to: string }> = ({ to }) => { + return ( +
+

It appears you already have this POAP 🎉

+

You should see it in your collection

+ + View Collection + +
+ ); +}; diff --git a/components/POAPModal/stages/ClaimError.tsx b/components/POAPModal/stages/ClaimError.tsx new file mode 100644 index 0000000..48dca9b --- /dev/null +++ b/components/POAPModal/stages/ClaimError.tsx @@ -0,0 +1,26 @@ +// eslint-disable-next-line unicorn/prefer-node-protocol, simple-import-sort/imports +import { inspect } from 'util'; +import { FC } from 'react'; +import { AlreadyClaimed } from './AlreadyClaimed'; + +export const ClaimError: FC<{ data: unknown; recipient: string }> = ({ + data, + recipient, +}) => { + if ( + data['statusCode'] == 400 && + data['error'] == 'Bad Request' && + data['message'] == 'You already minted a POAP for this drop.' + ) { + return ; + } + + return ( +
+

There was an error claiming this POAP.

+
+                {inspect(data)}
+            
+
+ ); +}; diff --git a/components/POAPModal/stages/Expired.tsx b/components/POAPModal/stages/Expired.tsx index 8c4605f..3b5443c 100644 --- a/components/POAPModal/stages/Expired.tsx +++ b/components/POAPModal/stages/Expired.tsx @@ -8,7 +8,7 @@ export const ExpiredPOAP: FC<{}> = () => { via the IYK Dashboard diff --git a/components/POAPModal/stages/MintToProfile.tsx b/components/POAPModal/stages/MintToProfile.tsx index 08a6de2..c04254b 100644 --- a/components/POAPModal/stages/MintToProfile.tsx +++ b/components/POAPModal/stages/MintToProfile.tsx @@ -3,6 +3,9 @@ import clsx from 'clsx'; import { FC, useState } from 'react'; import { FiCheck, FiLoader } from 'react-icons/fi'; +import { mintPOAP } from '../../../hooks/mintPOAP'; +import { IYKRefResponse as IYKReferenceResponse } from '../../../hooks/useIYKRef'; + const eth_address_regex = /^0x[\dA-Fa-f]{40}$/; export const MintToProfile: FC<{ @@ -11,7 +14,17 @@ export const MintToProfile: FC<{ event_name: string; onCallChange: () => void; onCallClose: () => void; -}> = ({ address, poap_name, event_name, onCallChange, onCallClose }) => { + iykData: IYKReferenceResponse; + onMintToProfileError: (error: unknown) => void; +}> = ({ + address, + poap_name, + event_name, + iykData, + onCallChange, + onCallClose, + onMintToProfileError, +}) => { const isAddress = eth_address_regex.test(address); const [stage, setStage] = useState<'start' | 'minting' | 'minted'>('start'); @@ -26,7 +39,7 @@ export const MintToProfile: FC<{ 'btn w-full py-3 space-x-2 transition-all', stage === 'minted' && '!bg-ens-light-green-primary' )} - onClick={() => { + onClick={async () => { if (stage === 'minted') { onCallClose(); @@ -35,9 +48,21 @@ export const MintToProfile: FC<{ setStage('minting'); - setTimeout(() => { + try { + const [data, error] = await mintPOAP( + iykData.poapEvents[0].otp, + address, + iykData.poapEvents[0].poapEventId + ); + + if (error) { + throw error; + } + setStage('minted'); - }, 1000); + } catch (error) { + onMintToProfileError(error); + } }} disabled={stage === 'minting'} > diff --git a/components/POAPModal/stages/NameInput.tsx b/components/POAPModal/stages/NameInput.tsx index a3deee7..c2ed172 100644 --- a/components/POAPModal/stages/NameInput.tsx +++ b/components/POAPModal/stages/NameInput.tsx @@ -61,9 +61,6 @@ export const NameInput: FC<{ disabled={loading} />
- {/* */}