diff --git a/components/SetHookDialog.tsx b/components/SetHookDialog.tsx index b19be63..c1818eb 100644 --- a/components/SetHookDialog.tsx +++ b/components/SetHookDialog.tsx @@ -1,7 +1,6 @@ import React, { useCallback, useEffect, useState } from "react"; import { Plus, Trash, X } from "phosphor-react"; -import Button from "./Button"; -import Box from "./Box"; +import { Button, Box, Text } from "."; import { Stack, Flex, Select } from "."; import { Dialog, @@ -19,48 +18,30 @@ import { useForm, } from "react-hook-form"; -import { TTS, tts } from "../utils/hookOnCalculator"; import { deployHook } from "../state/actions"; import { useSnapshot } from "valtio"; import state, { IFile, SelectOption } from "../state"; import toast from "react-hot-toast"; import { prepareDeployHookTx, sha256 } from "../state/actions/deployHook"; import estimateFee from "../utils/estimateFee"; - -const transactionOptions = Object.keys(tts).map(key => ({ - label: key, - value: key as keyof TTS, -})); - -export type SetHookData = { - Invoke: { - value: keyof TTS; - label: string; - }[]; - Fee: string; - HookNamespace: string; - HookParameters: { - HookParameter: { - HookParameterName: string; - HookParameterValue: string; - }; - }[]; - // HookGrants: { - // HookGrant: { - // Authorize: string; - // HookHash: string; - // }; - // }[]; -}; +import { + getParameters, + getInvokeOptions, + transactionOptions, + SetHookData, +} from "../utils/setHook"; +import { capitalize } from "../utils/helpers"; export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo( ({ accountAddress }) => { const snap = useSnapshot(state); + + const [estimateLoading, setEstimateLoading] = useState(false); + const [isSetHookDialogOpen, setIsSetHookDialogOpen] = useState(false); + const compiledFiles = snap.files.filter(file => file.compiledContent); const activeFile = compiledFiles[snap.activeWat] as IFile | undefined; - const [isSetHookDialogOpen, setIsSetHookDialogOpen] = useState(false); - const accountOptions: SelectOption[] = snap.accounts.map(acc => ({ label: acc.name, value: acc.address, @@ -75,12 +56,23 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo( const getHookNamespace = useCallback( () => - activeFile && snap.deployValues[activeFile.name] - ? snap.deployValues[activeFile.name].HookNamespace - : activeFile?.name.split(".")[0] || "", + (activeFile && snap.deployValues[activeFile.name]?.HookNamespace) || + activeFile?.name.split(".")[0] || + "", [activeFile, snap.deployValues] ); + const getDefaultValues = useCallback((): Partial => { + const content = activeFile?.compiledValueSnapshot; + return ( + (activeFile && snap.deployValues[activeFile.name]) || { + HookNamespace: getHookNamespace(), + Invoke: getInvokeOptions(content), + HookParameters: getParameters(content), + } + ); + }, [activeFile, getHookNamespace, snap.deployValues]); + const { register, handleSubmit, @@ -88,29 +80,25 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo( watch, setValue, getValues, + reset, formState: { errors }, } = useForm({ - defaultValues: (activeFile && snap.deployValues[activeFile.name]) || { - HookNamespace: activeFile?.name.split(".")[0] || "", - Invoke: transactionOptions.filter(to => to.label === "ttPAYMENT"), - }, + defaultValues: getDefaultValues(), }); const { fields, append, remove } = useFieldArray({ control, name: "HookParameters", // unique name for your Field Array }); - const [formInitialized, setFormInitialized] = useState(false); - const [estimateLoading, setEstimateLoading] = useState(false); + const watchedFee = watch("Fee"); - // Update value if activeFile changes + // Reset form if activeFile changes useEffect(() => { if (!activeFile) return; - const defaultValue = getHookNamespace(); + const defaultValues = getDefaultValues(); - setValue("HookNamespace", defaultValue); - setFormInitialized(true); - }, [setValue, activeFile, snap.deployValues, getHookNamespace]); + reset(defaultValues); + }, [activeFile, getDefaultValues, reset]); useEffect(() => { if ( @@ -141,23 +129,19 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo( calculateHashedValue(); }, [namespace, calculateHashedValue]); - // Calculate initial fee estimate when modal opens - useEffect(() => { - if (formInitialized && account) { - (async () => { - const formValues = getValues(); - const tx = await prepareDeployHookTx(account, formValues); - if (!tx) { - return; - } - const res = await estimateFee(tx, account); - if (res && res.base_fee) { - setValue("Fee", Math.round(Number(res.base_fee || "")).toString()); - } - })(); + const calculateFee = useCallback(async () => { + if (!account) return; + + const formValues = getValues(); + const tx = await prepareDeployHookTx(account, formValues); + if (!tx) { + return; } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [formInitialized]); + const res = await estimateFee(tx, account); + if (res && res.base_fee) { + setValue("Fee", Math.round(Number(res.base_fee || "")).toString()); + } + }, [account, getValues, setValue]); const tooLargeFile = () => { return Boolean( @@ -172,6 +156,12 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo( ); if (!account) return; if (currAccount) currAccount.isLoading = true; + + data.HookParameters.forEach(param => { + delete param.$metaData; + return param; + }); + const res = await deployHook(account, data); if (currAccount) currAccount.isLoading = false; @@ -181,8 +171,14 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo( } toast.error(`Transaction failed! (${res?.engine_result_message})`); }; + + const onOpenChange = useCallback((open: boolean) => { + setIsSetHookDialogOpen(open); + + if (open) calculateFee(); + }, [calculateFee]); return ( - + + + {errors.HookParameters?.[index]?.HookParameter + ?.HookParameterValue?.type === "required" && ( + This field is required )} - /> - - + + ))}