import { Check, CopyAll } from '@mui/icons-material' import clsx from 'clsx' import JSON5 from 'json5' import { ComponentType, useCallback, useEffect, useState } from 'react' import { SubmitHandler, useFormContext } from 'react-hook-form' import toast from 'react-hot-toast' import { useTranslation } from 'react-i18next' import { AddressInputProps, ContractSummary, LoadingDataWithError, QuerierForm, WalletChainSwitcherProps, } from '@dao-dao/types' import { makeValidateAddress, processError, validateRequired, } from '@dao-dao/utils' import { useChainContext } from '../contexts' import { Button } from './buttons' import { IconButton } from './icon_buttons' import { CodeMirrorInput, InputErrorMessage, InputLabel } from './inputs' import { Loader } from './logo' import { RawJsonDisplay } from './RawJsonDisplay' import { Tooltip } from './tooltip' export type QuerierProps = { queryContractSmart: (contractAddress: string, query: any) => Promise contractSummary: LoadingDataWithError availableQueries: LoadingDataWithError AddressInput: ComponentType> WalletChainSwitcher: ComponentType } export const Querier = ({ queryContractSmart, contractSummary, availableQueries, AddressInput, WalletChainSwitcher, }: QuerierProps) => { const { t } = useTranslation() const { chain: { bech32Prefix }, } = useChainContext() const { handleSubmit, control, watch, formState: { errors }, register, setValue, } = useFormContext() const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [result, setResult] = useState('') const [hasResult, setHasResult] = useState(false) const onSubmitForm: SubmitHandler = useCallback( async ({ contractAddress, query }) => { setLoading(true) try { const result = await queryContractSmart(contractAddress, query) console.log('Result', result) setResult(JSON.stringify(result, null, 2)) setError(null) setHasResult(true) } catch (err) { console.error(err) setError( processError(err, { forceCapture: false, }) ) setHasResult(false) } finally { setLoading(false) } }, [queryContractSmart] ) const contractAddress = watch('contractAddress') const query = watch('query') let queryJsonFormatError try { JSON5.parse(query) } catch (err) { queryJsonFormatError = err instanceof Error ? err.message : `${err}` } // Unset copied after 2 seconds unless it gets clicked again, then reset. const [copied, setCopied] = useState(0) useEffect(() => { if (!copied) { return } const timeout = setTimeout(() => setCopied(0), 2_000) return () => clearTimeout(timeout) }, [copied]) const CopyIcon = copied > 0 ? Check : CopyAll return (
{!contractSummary.loading && (contractSummary.errored ? ( ) : ( contractSummary.data.address === contractAddress && ( ) ))}
{!availableQueries.loading && !availableQueries.errored && !availableQueries.updating && availableQueries.data.length > 0 && (
{availableQueries.data.map((query) => ( ))}
)}
{loading ? ( ) : ( hasResult && ( { navigator.clipboard.writeText(result) setCopied((copied) => copied + 1) toast.success(t('info.copiedToClipboard')) }} size="sm" variant="ghost" /> ) )}
) }