Skip to content

Commit

Permalink
Merge pull request #42 from daqhris/fix-attestation-page
Browse files Browse the repository at this point in the history
Fix POAP retrieval issues
  • Loading branch information
daqhris authored Aug 11, 2024
2 parents 9f8b70a + b7ecbcd commit 5a351f6
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 70 deletions.
92 changes: 39 additions & 53 deletions components/EventAttendanceVerification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useState } from "react";
import Image from "next/image";
import { useEnsAddress } from "wagmi";
import axios from "axios";
import { eventIds } from "../event_ids.json";

interface POAPEvent {
chain: string;
Expand All @@ -15,53 +16,48 @@ interface POAPEvent {
event_id: string;
}

const EventAttendanceProof: React.FC<{ onVerified: () => void }> = ({ onVerified }) => {
const [inputAddress, setInputAddress] = useState("");
const EventAttendanceProof: React.FC<{ onVerified: () => void; setPoaps: React.Dispatch<React.SetStateAction<POAPEvent[]>>; userAddress: string }> = ({ onVerified, setPoaps, userAddress }) => {
const [isVerifying, setIsVerifying] = useState(false);
const [proofResult, setProofResult] = useState<string | null>(null);
const [poaps, setPOAPs] = useState<POAPEvent[]>([]);
const [localPoaps, setLocalPoaps] = useState<POAPEvent[]>([]);
const [missingPoaps, setMissingPoaps] = useState<string[]>([]);
const [imageLoadErrors, setImageLoadErrors] = useState<Record<string, boolean>>({});

const { data: ensAddress } = useEnsAddress({
name: inputAddress,
});
// ENS resolution is no longer needed as we're using the provided userAddress

const fetchPOAPs = useCallback(async (address: string) => {
const fetchPOAPs = useCallback(async () => {
setIsVerifying(true);
setProofResult(null);
setPOAPs([]);
setLocalPoaps([]);
setMissingPoaps([]);

const isValidAddress = /^(0x[a-fA-F0-9]{40}|.+\.eth)$/.test(address);
if (!isValidAddress) {
setProofResult("Invalid input. Please enter a valid Ethereum address or ENS name.");
setIsVerifying(false);
return;
}

try {
const response = await axios.get(`/api/fetchPoaps?address=${encodeURIComponent(address)}`);
const { poaps, missingEventIds, message } = response.data;
console.log(`Fetching POAPs for address: ${userAddress}`);
const response = await axios.get(`/api/fetchPoaps?address=${encodeURIComponent(userAddress)}`);
console.log('API response:', response.data);

const { poaps = [], missingEventIds = [], message = '' } = response.data;

if (Array.isArray(poaps) && poaps.length > 0) {
setPOAPs(poaps);
setMissingPoaps(missingEventIds);
// Ensure poaps is always an array
const validPoaps = Array.isArray(poaps) ? poaps : [];
setLocalPoaps(validPoaps);
setPoaps(validPoaps);
setMissingPoaps(Array.isArray(missingEventIds) ? missingEventIds : eventIds);

if (validPoaps.length > 0) {
if (missingEventIds.length === 0) {
setProofResult(`Proof successful! ${address} has all required POAPs for ETHGlobal Brussels 2024.`);
setProofResult(`Proof successful! ${userAddress} has the required POAPs for ETHGlobal Brussels 2024.`);
onVerified();
} else {
setProofResult(`${address} is missing ${missingEventIds.length} required POAPs for ETHGlobal Brussels 2024.`);
setProofResult(`${userAddress} has some POAPs but is missing ${missingEventIds.length} required POAPs for ETHGlobal Brussels 2024.`);
}
} else {
setPOAPs([]);
setMissingPoaps([]);
setProofResult(message || "No eligible POAPs found for ETHGlobal Brussels 2024.");
setProofResult(message || "No required POAPs were found for this address.");
}
} catch (error) {
console.error("Error fetching POAP data:", error);
setPOAPs([]);
setMissingPoaps([]);
setLocalPoaps([]);
setMissingPoaps(eventIds);
if (axios.isAxiosError(error)) {
if (error.response?.status === 400) {
setProofResult(error.response.data.error || "Invalid input. Please check your address and try again.");
Expand All @@ -78,13 +74,13 @@ const EventAttendanceProof: React.FC<{ onVerified: () => void }> = ({ onVerified
} finally {
setIsVerifying(false);
}
}, [onVerified]);
}, [onVerified, userAddress, setPoaps, eventIds]);

useEffect(() => {
if (ensAddress || inputAddress) {
fetchPOAPs(ensAddress || inputAddress);
if (userAddress) {
fetchPOAPs();
}
}, [ensAddress, inputAddress, fetchPOAPs]);
}, [userAddress, fetchPOAPs]);

const handleImageError = (tokenId: string) => {
setImageLoadErrors(prev => ({ ...prev, [tokenId]: true }));
Expand All @@ -94,35 +90,28 @@ const EventAttendanceProof: React.FC<{ onVerified: () => void }> = ({ onVerified
<div className="p-4 bg-white shadow rounded-lg">
<h2 className="text-2xl font-bold mb-4">Event Attendance Proof</h2>
<p className="mb-4">
Enter your Ethereum address or ENS name to provide proof of your attendance at ETHGlobal Brussels 2024:
Verifying your attendance at ETHGlobal Brussels 2024:
</p>
<input
type="text"
value={inputAddress}
onChange={e => setInputAddress(e.target.value)}
placeholder="Enter Ethereum address or ENS name"
className="w-full p-2 mb-4 border rounded"
/>
<button
onClick={() => fetchPOAPs(ensAddress || inputAddress)}
disabled={!inputAddress || isVerifying}
onClick={() => fetchPOAPs()}
disabled={isVerifying}
className="w-full bg-blue-500 text-white p-2 rounded hover:bg-blue-600 disabled:bg-gray-300 mb-4"
>
{isVerifying ? "Verifying..." : "Verify Attendance"}
</button>
{isVerifying && (
<p className="text-blue-500 mb-4">Verifying attendance for {ensAddress || inputAddress}...</p>
<p className="text-blue-500 mb-4">Verifying attendance for {userAddress}...</p>
)}
{poaps.length > 0 && (
{localPoaps && localPoaps.length > 0 && (
<div className="mt-4 bg-green-100 p-4 rounded">
<h3 className="text-lg font-semibold text-green-800 mb-2">POAPs Found</h3>
<p className="text-green-700 mb-4">
{missingPoaps.length === 0
{localPoaps.length === eventIds.length
? "You have all required POAPs for ETHGlobal Brussels 2024."
: `You have ${poaps.length} out of ${poaps.length + missingPoaps.length} required POAPs.`}
: `You have ${localPoaps.length} out of ${eventIds.length} required POAPs for ETHGlobal Brussels 2024.`}
</p>
<div className="flex flex-wrap">
{poaps.map((poap) => (
{localPoaps.map((poap) => (
<div key={poap.token_id} className="mr-4 mb-4">
<Image
src={imageLoadErrors[poap.token_id] ? "/placeholder-poap.png" : poap.image_url}
Expand All @@ -138,15 +127,12 @@ const EventAttendanceProof: React.FC<{ onVerified: () => void }> = ({ onVerified
</div>
</div>
)}
{missingPoaps.length > 0 && (
{missingPoaps && missingPoaps.length > 0 && (
<div className="mt-4 bg-yellow-100 p-4 rounded">
<h3 className="text-lg font-semibold text-yellow-800 mb-2">Missing POAPs</h3>
<p className="text-yellow-700 mb-2">You are missing the following POAPs:</p>
<ul className="list-disc list-inside">
{missingPoaps.map((eventId) => (
<li key={eventId}>Event ID: {eventId}</li>
))}
</ul>
<p className="text-yellow-700 mb-2">
The following POAPs were not found for your address: {missingPoaps.join(", ")}
</p>
</div>
)}
{proofResult && (
Expand Down
39 changes: 23 additions & 16 deletions pages/api/fetchPoaps.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import axios from 'axios';
import { readFileSync } from 'fs';
import path from 'path';

const eventIdsPath = path.join(process.cwd(), 'event_ids.json');
const { eventIds } = JSON.parse(readFileSync(eventIdsPath, 'utf8'));
const GNOSIS_EVENT_ID = '176328';
const TEST_ADDRESS = '0xb5ee030c71e76C3E03B2A8d425dBb9B395037C82';

export default async function handler(req, res) {
console.log('Incoming request:', {
Expand All @@ -14,18 +12,22 @@ export default async function handler(req, res) {
body: req.body
});

const { address } = req.query;
let { address } = req.query;

if (!address) {
console.error('Address is missing in the request');
return res.status(400).json({ error: 'Address is required' });
console.warn('Address is missing in the request, using test address');
address = TEST_ADDRESS;
}

try {
console.log(`Fetching POAPs for address: ${address}`);
const poapResponse = await axios.get(`https://api.poap.tech/actions/scan/${address}`, {
headers: {
'X-API-Key': process.env.POAP_API_KEY
},
params: {
chain: 'xdai', // Gnosis chain
event_id: GNOSIS_EVENT_ID
}
});

Expand All @@ -38,22 +40,27 @@ export default async function handler(req, res) {
const allPoaps = poapResponse.data;
console.log('Fetched POAPs:', JSON.stringify(allPoaps, null, 2));

const requiredPoaps = allPoaps.filter(poap => eventIds.includes(poap.event.id.toString()));
const missingEventIds = eventIds.filter(id => !requiredPoaps.some(poap => poap.event.id.toString() === id));
const requiredPoaps = allPoaps
.filter(poap => poap.event.id.toString() === GNOSIS_EVENT_ID)
.map(poap => ({
event: {
name: poap.event.name,
start_date: poap.event.start_date
},
tokenId: poap.tokenId
}));

if (requiredPoaps.length > 0) {
console.log(`Required POAPs found for address ${address}:`, JSON.stringify(requiredPoaps, null, 2));
console.log(`Required POAP found for address ${address}:`, JSON.stringify(requiredPoaps, null, 2));
res.status(200).json({
poaps: requiredPoaps,
missingEventIds: missingEventIds,
message: `Found ${requiredPoaps.length} out of ${eventIds.length} required POAPs.`
message: `Found POAP for ETHGlobal Brussels 2024 event (ID: ${GNOSIS_EVENT_ID}).`
});
} else {
console.log(`No required POAPs found for address ${address}`);
console.log(`No required POAP found for address ${address}`);
res.status(200).json({
poaps: [],
missingEventIds: eventIds,
message: "No required POAPs found for this address."
message: "No POAP found for ETHGlobal Brussels 2024 event for this address."
});
}
} catch (error) {
Expand All @@ -80,7 +87,7 @@ export default async function handler(req, res) {

if (error.response) {
if (error.response.status === 404) {
errorMessage = 'No POAPs found for this address.';
errorMessage = 'No POAPs found for this address on the Gnosis chain.';
statusCode = 404;
} else if (error.response.status === 401) {
errorMessage = 'Unauthorized access to POAP data. Please check API credentials.';
Expand Down
7 changes: 6 additions & 1 deletion pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const Home: React.FC = () => {
const [currentStage, setCurrentStage] = useState<Stage>("identity");
const [completedStages, setCompletedStages] = useState<Stage[]>([]);
const [poaps, setPoaps] = useState<POAPEvent[]>([]);
const [userAddress, setUserAddress] = useState<string>("");

useEffect(() => {
if (completedStages.length === 0 && currentStage !== "identity") {
Expand Down Expand Up @@ -55,12 +56,16 @@ const Home: React.FC = () => {
const renderCurrentStage = () => {
switch (currentStage) {
case "identity":
return <IdentityVerification onVerified={() => handleStageCompletion("identity")} />;
return <IdentityVerification onVerified={(address) => {
setUserAddress(address);
handleStageCompletion("identity");
}} />;
case "attendance":
return (
<EventAttendanceProof
onVerified={() => handleStageCompletion("attendance")}
setPoaps={setPoaps}
userAddress={userAddress}
/>
);
case "attestation":
Expand Down

0 comments on commit 5a351f6

Please sign in to comment.