-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3fe95d4
commit d8e63b2
Showing
13 changed files
with
296 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
"use client"; | ||
|
||
import React, { useState } from "react"; | ||
import { useRouter } from "next/navigation"; | ||
import SubmitButton from "./SubmitButton"; | ||
import { useMutation } from "@tanstack/react-query"; | ||
import { useAccount, useSignTypedData } from "wagmi"; | ||
import { CreateNewSubmissionBody } from "~~/app/api/submissions/route"; | ||
import { EIP_712_DOMAIN, EIP_712_TYPES__SUBMISSION } from "~~/utils/eip712"; | ||
import { postMutationFetcher } from "~~/utils/react-query"; | ||
import { notification } from "~~/utils/scaffold-eth"; | ||
|
||
const MAX_DESCRIPTION_LENGTH = 750; | ||
|
||
const Form = () => { | ||
const { address: connectedAddress } = useAccount(); | ||
const [descriptionLength, setDescriptionLength] = useState(0); | ||
const { signTypedDataAsync } = useSignTypedData(); | ||
const router = useRouter(); | ||
const { mutateAsync: postNewSubmission } = useMutation({ | ||
mutationFn: (newSubmission: CreateNewSubmissionBody) => | ||
postMutationFetcher("/api/submissions", { body: newSubmission }), | ||
}); | ||
|
||
const clientFormAction = async (formData: FormData) => { | ||
if (!connectedAddress) { | ||
notification.error("Please connect your wallet"); | ||
return; | ||
} | ||
|
||
try { | ||
const title = formData.get("title") as string; | ||
const description = formData.get("description") as string; | ||
const linkToRepository = formData.get("linkToRepository") as string; | ||
if (!title || !description || !linkToRepository) { | ||
notification.error("Please fill all the fields"); | ||
return; | ||
} | ||
|
||
const signature = await signTypedDataAsync({ | ||
domain: EIP_712_DOMAIN, | ||
types: EIP_712_TYPES__SUBMISSION, | ||
primaryType: "Message", | ||
message: { | ||
title: title, | ||
description: description, | ||
linkToRepository: linkToRepository, | ||
}, | ||
}); | ||
|
||
await postNewSubmission({ title, description, linkToRepository, signature, signer: connectedAddress }); | ||
|
||
notification.success("Extension submitted successfully!"); | ||
router.push("/"); | ||
} catch (error: any) { | ||
if (error instanceof Error) { | ||
notification.error(error.message); | ||
return; | ||
} | ||
notification.error("Something went wrong"); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className="card card-compact rounded-xl max-w-[95%] w-[500px] bg-secondary shadow-lg mb-12"> | ||
<form action={clientFormAction} className="card-body space-y-3"> | ||
<h2 className="card-title self-center text-3xl !mb-0">Submit Extension</h2> | ||
<div className="space-y-2"> | ||
<p className="m-0 text-xl ml-2">Title</p> | ||
<div className="flex border-2 border-base-300 bg-base-200 rounded-xl text-accent"> | ||
<input | ||
className="input input-ghost focus-within:border-transparent focus:outline-none focus:bg-transparent focus:text-gray-400 h-[2.2rem] min-h-[2.2rem] px-4 border w-full font-medium placeholder:text-accent/50 text-gray-400" | ||
placeholder="Extension title" | ||
name="title" | ||
autoComplete="off" | ||
type="text" | ||
maxLength={75} | ||
/> | ||
</div> | ||
</div> | ||
<div className="space-y-2"> | ||
<p className="m-0 text-xl ml-2">Description</p> | ||
<div className="flex flex-col border-2 border-base-300 bg-base-200 rounded-xl text-accent"> | ||
<textarea | ||
className="input input-ghost focus-within:border-transparent focus:outline-none focus:bg-transparent focus:text-gray-400 px-4 pt-2 border w-full font-medium placeholder:text-accent/50 text-gray-400 h-28 md:h-52 rounded-none" | ||
placeholder="Extension description" | ||
name="description" | ||
autoComplete="off" | ||
maxLength={MAX_DESCRIPTION_LENGTH} | ||
onChange={e => setDescriptionLength(e.target.value.length)} | ||
/> | ||
<p className="my-1"> | ||
{descriptionLength} / {MAX_DESCRIPTION_LENGTH} | ||
</p> | ||
</div> | ||
</div> | ||
<div className="space-y-2"> | ||
<p className="m-0 text-xl ml-2">Repository URL</p> | ||
<div className="flex border-2 border-base-300 bg-base-200 rounded-xl text-accent"> | ||
<input | ||
className="input input-ghost focus-within:border-transparent focus:outline-none focus:bg-transparent focus:text-gray-400 h-[2.2rem] min-h-[2.2rem] px-4 border w-full font-medium placeholder:text-accent/50 text-gray-400" | ||
placeholder="https://" | ||
name="linkToRepository" | ||
autoComplete="off" | ||
type="text" | ||
maxLength={75} | ||
/> | ||
</div> | ||
</div> | ||
<SubmitButton /> | ||
</form> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Form; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
"use client"; | ||
|
||
import { useFormStatus } from "react-dom"; | ||
import { useAccount } from "wagmi"; | ||
import { RainbowKitCustomConnectButton } from "~~/components/scaffold-eth"; | ||
|
||
// To use useFormStatus we need to make sure button is child of form | ||
const SubmitButton = () => { | ||
const { pending } = useFormStatus(); | ||
const { isConnected } = useAccount(); | ||
|
||
return ( | ||
<div | ||
className={`flex ${!isConnected && "tooltip tooltip-bottom"}`} | ||
data-tip={`${!isConnected ? "Please connect your wallet" : ""}`} | ||
> | ||
{isConnected ? ( | ||
<button className="btn btn-primary w-full" disabled={pending} aria-disabled={pending}> | ||
Submit | ||
</button> | ||
) : ( | ||
<RainbowKitCustomConnectButton fullWidth={true} /> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default SubmitButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Form from "./_component/Form"; | ||
import { NextPage } from "next"; | ||
|
||
const Submit: NextPage = () => { | ||
return ( | ||
<div className="flex bg-base-100 items-center flex-col flex-grow text-center pt-10 md:pt-4 px-6"> | ||
<h1 className="text-3xl sm:text-4xl font-bold mb-4">Submit Extension</h1> | ||
<p className="text-md mb-0 max-w-xl">Submit your SE-2 extension.</p> | ||
<Form /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Submit; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
packages/nextjs/services/database/repositories/builders.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { InferInsertModel, eq } from "drizzle-orm"; | ||
import { db } from "~~/services/database/config/postgresClient"; | ||
import { builders } from "~~/services/database/config/schema"; | ||
|
||
export type BuilderInsert = InferInsertModel<typeof builders>; | ||
|
||
export async function getAllBuilders() { | ||
return await db.select().from(builders); | ||
} | ||
|
||
export async function getBuilderById(id: string) { | ||
return await db.query.builders.findFirst({ where: eq(builders.id, id) }); | ||
} | ||
|
||
export async function createBuilder(builder: BuilderInsert) { | ||
return await db.insert(builders).values(builder); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export const EIP_712_DOMAIN = { | ||
name: "Scaffold-ETH 2 Extensions Hackathon", | ||
version: "1", | ||
} as const; | ||
|
||
export const EIP_712_TYPES__SUBMISSION = { | ||
Message: [ | ||
{ name: "title", type: "string" }, | ||
{ name: "description", type: "string" }, | ||
{ name: "linkToRepository", type: "string" }, | ||
], | ||
} as const; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
export const fetcher = async <T = Record<any, any>>(...args: Parameters<typeof fetch>) => { | ||
const res = await fetch(...args); | ||
const data = await res.json(); | ||
if (!res.ok) { | ||
throw new Error(data.error || "Error fetching data"); | ||
} | ||
return data as T; | ||
}; | ||
|
||
export const makeMutationFetcher = | ||
<T = Record<any, any>>(method: "POST" | "PUT" | "PATCH" | "DELETE") => | ||
async (url: string, { body }: { body: T }) => { | ||
const res = await fetch(url, { | ||
method: method, | ||
body: JSON.stringify(body), | ||
}); | ||
|
||
const data = await res.json(); | ||
|
||
if (!res.ok) { | ||
throw new Error(data.error || `Error ${method.toLowerCase()}ing data`); | ||
} | ||
return data; | ||
}; | ||
|
||
export const postMutationFetcher = <T = Record<any, any>>(url: string, arg: { body: T }) => | ||
makeMutationFetcher<T>("POST")(url, arg); | ||
|
||
export const patchMutationFetcher = <T = Record<any, any>>(url: string, arg: { body: T }) => | ||
makeMutationFetcher<T>("PATCH")(url, arg); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters