diff --git a/prisma/migrations/20240325152421_add_mint_request/migration.sql b/prisma/migrations/20240325152421_add_mint_request/migration.sql
new file mode 100644
index 00000000..75e0c969
--- /dev/null
+++ b/prisma/migrations/20240325152421_add_mint_request/migration.sql
@@ -0,0 +1,13 @@
+-- CreateTable
+CREATE TABLE "MintRequest" (
+ "id" SERIAL NOT NULL,
+ "userId" INTEGER NOT NULL,
+ "walletAddress" TEXT NOT NULL,
+ "stringifiedPublicKeys" TEXT NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+
+ CONSTRAINT "MintRequest_pkey" PRIMARY KEY ("id")
+);
+
+-- AddForeignKey
+ALTER TABLE "MintRequest" ADD CONSTRAINT "MintRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index fd58b56e..cba8f272 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -38,6 +38,7 @@ model User {
admin Admin?
buidlMint BuidlMint[]
itemRedeemed ItemRedeemed[]
+ MintRequest MintRequest[]
}
model Admin {
@@ -119,7 +120,7 @@ model Quest {
summonId String? @unique
buidlReward Int
itemId Int? @unique
- priority Int @default(0)
+ priority Int @default(0)
isHidden Boolean @default(false)
createdAt DateTime @default(now())
userRequirements UserRequirement[]
@@ -248,3 +249,12 @@ model ItemRedeemed {
user User @relation(fields: [userId], references: [id])
item Item @relation(fields: [itemId], references: [id])
}
+
+model MintRequest {
+ id Int @id @default(autoincrement())
+ userId Int
+ walletAddress String
+ stringifiedPublicKeys String
+ createdAt DateTime @default(now())
+ user User @relation(fields: [userId], references: [id])
+}
diff --git a/src/pages/api/mint/art.ts b/src/pages/api/mint/art.ts
new file mode 100644
index 00000000..b3d563dc
--- /dev/null
+++ b/src/pages/api/mint/art.ts
@@ -0,0 +1,54 @@
+import type { NextApiRequest, NextApiResponse } from "next";
+import prisma from "@/lib/server/prisma";
+import { verifyAuthToken } from "@/lib/server/auth";
+
+interface MintRequest {
+ authToken: string;
+ walletAddress: string;
+ stringifiedPublicKeys: string;
+}
+
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse
+) {
+ if (req.method !== "POST") {
+ return res.status(405).json({ message: "Method not allowed" });
+ }
+
+ try {
+ const { authToken, walletAddress, stringifiedPublicKeys }: MintRequest =
+ req.body;
+
+ if (!authToken || !walletAddress || !stringifiedPublicKeys) {
+ return res.status(400).json({ message: "Missing required fields" });
+ }
+
+ const userId = await verifyAuthToken(authToken);
+ if (!userId) {
+ return res.status(401).json({ message: "Invalid or expired authToken" });
+ }
+
+ const existingMintRequest = await prisma.mintRequest.findFirst({
+ where: { userId },
+ });
+ if (existingMintRequest) {
+ return res
+ .status(400)
+ .json({ message: "User already has a mint request" });
+ }
+
+ await prisma.mintRequest.create({
+ data: {
+ userId: userId,
+ walletAddress,
+ stringifiedPublicKeys,
+ },
+ });
+
+ return res.status(200).json({});
+ } catch (error) {
+ console.error("Request error: ", error);
+ res.status(500).json({ message: "Error processing request" });
+ }
+}
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 1f5b4c4e..26ccb7d3 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -510,7 +510,10 @@ export default function Social() {
- {claveInfo?.claveWalletAddress ? (
+
+
+
+ {/* {claveInfo?.claveWalletAddress ? (
@@ -525,7 +528,7 @@ export default function Social() {
) : (
<>>
- )}
+ )} */}
diff --git a/src/pages/mint/index.tsx b/src/pages/mint/index.tsx
new file mode 100644
index 00000000..74c9279f
--- /dev/null
+++ b/src/pages/mint/index.tsx
@@ -0,0 +1,103 @@
+import { Button } from "@/components/Button";
+import { Input } from "@/components/Input";
+import { FormStepLayout } from "@/layouts/FormStepLayout";
+import {
+ getAuthToken,
+ getLocationSignatures,
+ getUsers,
+} from "@/lib/client/localStorage";
+import Link from "next/link";
+import { useRouter } from "next/router";
+import { useState } from "react";
+import { toast } from "sonner";
+
+const MintPage = () => {
+ const [walletAddress, setWalletAddress] = useState("");
+ const [loading, setLoading] = useState(false);
+ const router = useRouter();
+
+ const handleMint = async (event: React.FormEvent) => {
+ event.preventDefault();
+ if (!walletAddress || walletAddress.slice(0, 2) !== "0x") {
+ toast.error("Please enter a valid wallet address 0x...");
+ return;
+ }
+ setLoading(true);
+
+ const token = getAuthToken();
+ if (!token) {
+ toast.error("You must be logged in to mint an NFT");
+ setLoading(false);
+ return;
+ }
+
+ const users = getUsers();
+ const userSignaturePublicKeys: string[] = Object.values(users)
+ .filter((user) => user.sigPk && user.inTs)
+ .map((user) => user.sigPk!);
+
+ const locations = getLocationSignatures();
+ const locationSignaturePublicKeys: string[] = Object.values(locations)
+ .filter((location) => location.pk)
+ .map((location) => location.pk);
+
+ const stringifiedPublicKeys = JSON.stringify({
+ users: userSignaturePublicKeys,
+ locations: locationSignaturePublicKeys,
+ });
+
+ const response = await fetch("/api/mint/art", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ authToken: token.value,
+ walletAddress,
+ stringifiedPublicKeys,
+ }),
+ });
+
+ if (!response.ok) {
+ const error = await response.json();
+ console.error("Error minting NFT: ", error.messsage);
+ toast.error("Error minting NFT! Please try again later.");
+ } else {
+ toast.info(
+ "Successfully processed mint request - please wait a few days for the NFT to be minted."
+ );
+ }
+ setLoading(false);
+
+ router.push("/");
+ };
+
+ return (
+
+
+
+ Back
+
+
+ }
+ >
+ setWalletAddress(event.target.value)}
+ required
+ />
+
+ );
+};
+export default MintPage;