diff --git a/packages/nextjs/app/admin/_components/EditGrantModal.tsx b/packages/nextjs/app/admin/_components/EditGrantModal.tsx new file mode 100644 index 00000000..9a51274e --- /dev/null +++ b/packages/nextjs/app/admin/_components/EditGrantModal.tsx @@ -0,0 +1,148 @@ +import { ChangeEvent, forwardRef, useState } from "react"; +import { useSWRConfig } from "swr"; +import useSWRMutation from "swr/mutation"; +import { useAccount, useNetwork, useSignTypedData } from "wagmi"; +import { GrantDataWithBuilder } from "~~/services/database/schema"; +import { EIP_712_DOMAIN, EIP_712_TYPES__EDIT_GRANT } from "~~/utils/eip712"; +import { getParsedError, notification } from "~~/utils/scaffold-eth"; +import { patchMutationFetcher } from "~~/utils/swr"; + +type EditGrantModalProps = { + grant: GrantDataWithBuilder; + closeModal: () => void; +}; + +type ReqBody = { + title?: string; + description?: string; + askAmount?: number; + signature?: `0x${string}`; + signer?: string; +}; + +export const EditGrantModal = forwardRef(({ grant, closeModal }, ref) => { + const [formData, setFormData] = useState({ + title: grant.title, + description: grant.description, + askAmount: grant.askAmount.toString(), + }); + + const { address } = useAccount(); + const { chain: connectedChain } = useNetwork(); + const { signTypedDataAsync, isLoading: isSigningMessage } = useSignTypedData(); + + const { trigger: editGrant, isMutating } = useSWRMutation(`/api/grants/${grant.id}`, patchMutationFetcher); + const { mutate } = useSWRConfig(); + + const isLoading = isSigningMessage || isMutating; + + const handleInputChange = (e: ChangeEvent) => { + const { name, value } = e.target; + setFormData(prevFormData => ({ + ...prevFormData, + [name]: value, + })); + }; + + const handleEditGrant = async () => { + if (!address || !connectedChain) { + notification.error("Please connect your wallet"); + return; + } + + let notificationId: string | undefined; + try { + const signature = await signTypedDataAsync({ + domain: EIP_712_DOMAIN, + types: EIP_712_TYPES__EDIT_GRANT, + primaryType: "Message", + message: { + grantId: grant.id, + title: formData.title, + description: formData.description, + // Converting this to number with parseFloat and again to string (similar to backend), + // if not it generates different signature with .23 and 0.23 + askAmount: parseFloat(formData.askAmount).toString(), + }, + }); + notificationId = notification.loading("Updating grant"); + await editGrant({ + signer: address, + signature, + ...formData, + askAmount: parseFloat(formData.askAmount), + }); + await mutate("/api/grants/review"); + notification.remove(notificationId); + notification.success(`Successfully updated grant ${grant.id}`); + closeModal(); + } catch (error) { + console.error("Error editing grant", error); + const errorMessage = getParsedError(error); + notification.error(errorMessage); + } finally { + if (notificationId) notification.remove(notificationId); + } + }; + + return ( + +
+
+ {/* if there is a button in form, it will close the modal */} + +
+
+

+ Edit grant + ({grant.id}) +

+
+
+

Title

+ +
+
+

Description

+