Skip to content

Commit

Permalink
basic iteration with api
Browse files Browse the repository at this point in the history
  • Loading branch information
technophile-04 committed Aug 31, 2024
1 parent 49f2090 commit da21df2
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { isAddress } from "viem";

type Data = {
isEligible: boolean;
type: "builder" | "batch" | null;
};

type ErrorResponse = {
error: string;
};

export default function handler(req: NextApiRequest, res: NextApiResponse<Data | ErrorResponse>) {
const { builderAddress } = req.query;

if (typeof builderAddress !== "string") {
return res.status(400).json({ error: "Invalid builder address" });
}

// Validate the builder address
if (!isAddress(builderAddress)) {
return res.status(400).json({ error: "Invalid Ethereum address" });
}

const isEligible = Math.random() > 0.5;
const type = isEligible ? (Math.random() > 0.5 ? "builder" : "batch") : null;

res.status(200).json({ isEligible, type });
}
49 changes: 49 additions & 0 deletions packages/nextjs/pages/api/devcon/get-voucher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { isAddress, verifyMessage } from "viem";

type RequestBody = {
signature: `0x${string}`;
message: string;
builderAddress: string;
};

type SuccessResponse = {
voucher: string;
};

type ErrorResponse = {
error: string;
};

export default async function handler(req: NextApiRequest, res: NextApiResponse<SuccessResponse | ErrorResponse>) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method Not Allowed" });
}

const { signature, message, builderAddress } = req.body as RequestBody;

if (!signature || !message || !builderAddress) {
return res.status(400).json({ error: "Missing required fields" });
}

if (!isAddress(builderAddress)) {
return res.status(400).json({ error: "Invalid Ethereum address" });
}

try {
const isValid = await verifyMessage({
address: builderAddress,
message,
signature,
});

if (!isValid) {
return res.status(401).json({ error: "Invalid signature" });
}
} catch (error) {
return res.status(400).json({ error: "Signature verification failed" });
}
const voucher = Math.random().toString(36).substring(2, 8).toUpperCase();

res.status(200).json({ voucher });
}
87 changes: 63 additions & 24 deletions packages/nextjs/pages/devcon-2024/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,64 @@ const ConnectButton = () => {
};

const Devon2024 = () => {
const [isEligible, setIsEligible] = useState(false);

const [eligibilityStatus, setEligibilityStatus] = useState<{ isEligible: boolean; type: string | null } | null>(null);
const [voucher, setVoucher] = useState<string | null>(null);
const { address: connectedAddress, isConnected } = useAccount();
const [inputAddress, setInputAddress] = useState(connectedAddress || "");
const [inputAddress, setInputAddress] = useState("");
const { isLoading: isSigningMessage, signMessageAsync } = useSignMessage({
message: `I want to claim Devon Bangkok 2024 for ${connectedAddress}`,
});

// need this prevent hydration mismatch because of isConnect
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);

useEffect(() => {
if (connectedAddress) {
setInputAddress(connectedAddress);
}
}, [connectedAddress]);

const handleCheckEligibility = () => {
setIsEligible(!isEligible);
const handleCheckEligibility = async () => {
try {
const response = await fetch(`/api/devcon/check-eligibility/${inputAddress}`);
if (!response.ok) {
throw new Error("Failed to check eligibility");
}
const data = await response.json();
setEligibilityStatus(data);
if (data.isEligible) {
notification.success(`Congratulations! You're eligible for ${data.type} discount.`);
} else {
notification.error("Sorry, you're not eligible for a discount.");
}
} catch (e) {
const error = getParsedError(e);
notification.error(error);
}
};

const getVoucher = async () => {
try {
const signature = await signMessageAsync();
console.log("Signature: ", signature);
const response = await fetch("/api/devcon/get-voucher", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
signature,
message: `I want to claim Devon Bangkok 2024 for ${connectedAddress}`,
builderAddress: connectedAddress,
}),
});
if (!response.ok) {
throw new Error("Failed to get voucher");
}
const data = await response.json();
setVoucher(data.voucher);
} catch (e) {
const error = getParsedError(e);
notification.error(error);
Expand All @@ -46,8 +82,8 @@ const Devon2024 = () => {
return (
<>
<MetaHeader />
<div className="hero min-h-screen bg-base-200">
<div className="card w-96 bg-base-100 shadow-xl">
<div className="hero min-h-screen bg-base-100">
<div className="card w-96 bg-base-300 shadow-xl">
<div className="card-body items-center text-center">
<h1 className="card-title text-3xl font-bold">Check Your Eligibility</h1>
<div className="flex flex-col gap-4">
Expand All @@ -56,26 +92,29 @@ const Devon2024 = () => {
<button className="btn btn-primary" onClick={handleCheckEligibility}>
Check Eligibility
</button>
{!isConnected ? (
<ConnectButton />
) : (
<button
className={`btn btn-primary ${isSigningMessage ? "loading" : ""}`}
disabled={isSigningMessage}
onClick={getVoucher}
>
Get Voucher
</button>
)}
{isClient ? (
!isConnected ? (
<ConnectButton />
) : (
<button
className={`btn btn-primary ${isSigningMessage ? "loading" : ""}`}
disabled={isSigningMessage || !eligibilityStatus?.isEligible}
onClick={getVoucher}
>
Get Voucher
</button>
)
) : null}
</div>

{isEligible && (
{eligibilityStatus?.isEligible && (
<p className="mt-4">🥳 Congratulations! You&apos;re eligible for {eligibilityStatus.type} discount.</p>
)}
{voucher && (
<>
<div className="divider"></div>
<div>
<h2 className="text-2xl font-bold mb-4">Congratulations! You&apos;re Eligible</h2>
<p className="mb-4">Here&apos;s your voucher code:</p>
<div className="bg-secondary text-primary-content p-4 rounded-lg text-2xl font-bold">332421</div>
<h2 className="text-2xl font-bold mb-4">Here&apos;s Your Voucher Code</h2>
<div className="bg-secondary text-primary-content p-4 rounded-lg text-2xl font-bold">{voucher}</div>
<p className="mt-4">Use this code to redeem your special offer.</p>
</div>
</>
Expand Down

0 comments on commit da21df2

Please sign in to comment.