From fd139598bfe1e2db7217d682a25b130572eb5caf Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 21 Dec 2022 16:58:55 +0700 Subject: [PATCH 01/27] feat: execute msgs cmd shown when wallet is not connected --- package.json | 1 + src/env.ts | 2 + src/lib/app-provider/index.ts | 1 + src/lib/app-provider/queries/simulateFee.ts | 39 ++++++++++--- src/lib/hooks/index.ts | 1 + src/lib/hooks/useDummyWallet.ts | 30 ++++++++++ src/lib/pages/execute/hook/useExecuteCmds.ts | 45 +++++++++++++++ src/lib/pages/execute/index.tsx | 41 ++++---------- yarn.lock | 59 +++++++++++++++++++- 9 files changed, 181 insertions(+), 38 deletions(-) create mode 100644 src/lib/hooks/useDummyWallet.ts create mode 100644 src/lib/pages/execute/hook/useExecuteCmds.ts diff --git a/package.json b/package.json index 2ed9b33a4..13a28dda3 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@chakra-ui/react": "^2.3.6", "@chakra-ui/styled-system": "^2.3.5", "@cosmjs/cosmwasm-stargate": "^0.29.3", + "@cosmjs/proto-signing": "^0.29.5", "@cosmjs/stargate": "^0.29.3", "@cosmos-kit/core": "^0.20.0", "@cosmos-kit/keplr": "^0.20.0", diff --git a/src/env.ts b/src/env.ts index 8d90c643c..24e29e7f7 100644 --- a/src/env.ts +++ b/src/env.ts @@ -54,3 +54,5 @@ export const CELATONE_CONSTANTS: CelatoneConstants = { maxFileSize: MAX_FILE_SIZE, msgTypeUrl: MSG_TYPE_URL, }; + +export const { DUMMY_MNEMONIC } = process.env; diff --git a/src/lib/app-provider/index.ts b/src/lib/app-provider/index.ts index 08198e52c..62c83435a 100644 --- a/src/lib/app-provider/index.ts +++ b/src/lib/app-provider/index.ts @@ -1,3 +1,4 @@ export * from "./hooks"; export * from "./tx"; export * from "./contexts"; +export * from "./queries"; diff --git a/src/lib/app-provider/queries/simulateFee.ts b/src/lib/app-provider/queries/simulateFee.ts index 1c4945c62..d6b455f83 100644 --- a/src/lib/app-provider/queries/simulateFee.ts +++ b/src/lib/app-provider/queries/simulateFee.ts @@ -1,6 +1,8 @@ +import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; import { useWallet } from "@cosmos-kit/react"; import { useQuery } from "@tanstack/react-query"; +import { useDummyWallet } from "lib/hooks"; import type { ComposedMsg, Gas } from "lib/types"; interface SimulateQueryParams { @@ -16,21 +18,42 @@ export const useSimulateFeeQuery = ({ onSuccess, onError, }: SimulateQueryParams) => { - const { address, getCosmWasmClient, currentChainName } = useWallet(); + const { address, getCosmWasmClient, currentChainName, currentChainRecord } = + useWallet(); + const { dummyWallet, dummyAddress } = useDummyWallet(); + const simulateFn = async (msgs: ComposedMsg[]) => { - const client = await getCosmWasmClient(); - if (!client || !address) { + let client = await getCosmWasmClient(); + if ( + !currentChainRecord || + !currentChainRecord.preferredEndpoints || + !currentChainRecord.preferredEndpoints.rpc || + !currentChainRecord.preferredEndpoints.rpc[0] + ) { return Promise.resolve(undefined); } - return (await client.simulate(address, msgs, undefined)) as Gas; + + if (!client && !address && dummyWallet) { + client = await SigningCosmWasmClient.connectWithSigner( + currentChainRecord.preferredEndpoints.rpc[0], + dummyWallet + ); + } + + if (!client || !dummyAddress) { + return Promise.resolve(undefined); + } + + return (await client.simulate( + address || dummyAddress, + msgs, + undefined + )) as Gas; }; - // TODO: make this as query key constant return useQuery({ queryKey: ["simulate", currentChainName, address, messages], - queryFn: async ({ queryKey }) => { - return simulateFn(queryKey[3] as ComposedMsg[]); - }, + queryFn: async ({ queryKey }) => simulateFn(queryKey[3] as ComposedMsg[]), enabled, keepPreviousData: true, retry: false, diff --git a/src/lib/hooks/index.ts b/src/lib/hooks/index.ts index 25d944420..bc955d10c 100644 --- a/src/lib/hooks/index.ts +++ b/src/lib/hooks/index.ts @@ -3,3 +3,4 @@ export * from "./useMediaQuery"; export * from "./useToast"; export * from "./useEndpoint"; export * from "./useUserKey"; +export * from "./useDummyWallet"; diff --git a/src/lib/hooks/useDummyWallet.ts b/src/lib/hooks/useDummyWallet.ts new file mode 100644 index 000000000..63d95ea9f --- /dev/null +++ b/src/lib/hooks/useDummyWallet.ts @@ -0,0 +1,30 @@ +import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; +import { useWallet } from "@cosmos-kit/react"; +import { useEffect, useState } from "react"; + +import { DUMMY_MNEMONIC } from "env"; + +export const useDummyWallet = () => { + const { currentChainRecord } = useWallet(); + const [dummyWallet, setDummyWallet] = useState(); + const [dummyAddress, setDummyAddress] = useState(); + useEffect(() => { + const getData = async () => { + const wallet = await DirectSecp256k1HdWallet.fromMnemonic( + DUMMY_MNEMONIC || "", + { + prefix: currentChainRecord?.chain.bech32_prefix, + } + ); + + setDummyWallet(wallet); + + const { address } = (await wallet.getAccounts())[0]; + setDummyAddress(address); + }; + + getData(); + }, [currentChainRecord?.chain.bech32_prefix]); + + return { dummyWallet, dummyAddress }; +}; diff --git a/src/lib/pages/execute/hook/useExecuteCmds.ts b/src/lib/pages/execute/hook/useExecuteCmds.ts new file mode 100644 index 000000000..2d43273d3 --- /dev/null +++ b/src/lib/pages/execute/hook/useExecuteCmds.ts @@ -0,0 +1,45 @@ +import { useWallet } from "@cosmos-kit/react"; +import { useState } from "react"; + +import { useSimulateFeeQuery } from "lib/app-provider"; +import { useDummyWallet } from "lib/hooks"; +import type { HumanAddr, ContractAddr } from "lib/types"; +import { MsgType } from "lib/types"; +import { composeMsg } from "lib/utils"; + +interface UseExecuteCmdsProps { + contractAddress: string; +} +export const useExecuteCmds = ({ contractAddress }: UseExecuteCmdsProps) => { + const [isEmptyContractAddress, setIsEmptyContractAddress] = + useState(false); + const [execCmds, setExecCmds] = useState<[string, string][]>([]); + const { address } = useWallet(); + const { dummyAddress } = useDummyWallet(); + + // TODO - Refactor - use useSimulateFee + const { isFetching } = useSimulateFeeQuery({ + enabled: !!contractAddress, + messages: [ + composeMsg(MsgType.EXECUTE, { + sender: (address || dummyAddress) as HumanAddr, + contract: contractAddress as ContractAddr, + msg: Buffer.from('{"": {}}'), + funds: [], + }), + ], + onError: (e) => { + if (e.message.includes("contract: ")) { + setIsEmptyContractAddress(true); + setExecCmds([]); + } else { + const executeCmds: string[] = []; + Array.from(e.message?.matchAll(/`(.*?)`/g) || []) + .slice(1) + .forEach((match) => executeCmds.push(match[1])); + setExecCmds(executeCmds.map((cmd) => [cmd, `{"${cmd}": {}}`])); + } + }, + }); + return { isFetching, isEmptyContractAddress, execCmds }; +}; diff --git a/src/lib/pages/execute/index.tsx b/src/lib/pages/execute/index.tsx index 90a80ce41..c84d9e4bb 100644 --- a/src/lib/pages/execute/index.tsx +++ b/src/lib/pages/execute/index.tsx @@ -1,10 +1,8 @@ import { ArrowBackIcon } from "@chakra-ui/icons"; import { Heading, Button, Box, Flex, Text } from "@chakra-ui/react"; -import { useWallet } from "@cosmos-kit/react"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; -import { useSimulateFeeQuery } from "lib/app-provider/queries"; import { ConnectWalletAlert } from "lib/components/ConnectWalletAlert"; import { ExplorerLink } from "lib/components/ExplorerLink"; import { LoadingOverlay } from "lib/components/LoadingOverlay"; @@ -12,23 +10,21 @@ import { SelectContract } from "lib/components/modal/select-contract"; import PageContainer from "lib/components/PageContainer"; import { useContractStore, useEndpoint, useMobile } from "lib/hooks"; import { queryContract } from "lib/services/contract"; -import type { ContractAddr, HumanAddr } from "lib/types"; -import { MsgType } from "lib/types"; import { getFirstQueryParam, decode, jsonPrettify, jsonValidate, - composeMsg, } from "lib/utils"; import { ExecuteArea } from "./components/ExecuteArea"; +import { useExecuteCmds } from "./hook/useExecuteCmds"; const Execute = () => { const router = useRouter(); const isMobile = useMobile(); const { getContractInfo } = useContractStore(); - const { address = "" } = useWallet(); + const endpoint = useEndpoint(); const [contractAddress, setContractAddress] = useState(""); @@ -36,6 +32,10 @@ const Execute = () => { const [initialMsg, setInitialMsg] = useState(""); const [cmds, setCmds] = useState<[string, string][]>([]); + const { isFetching, isEmptyContractAddress, execCmds } = useExecuteCmds({ + contractAddress, + }); + const goToQuery = () => { router.push({ pathname: "/query", @@ -56,29 +56,12 @@ const Execute = () => { [router] ); - const { isFetching } = useSimulateFeeQuery({ - enabled: !!contractAddress, - messages: [ - composeMsg(MsgType.EXECUTE, { - sender: address as HumanAddr, - contract: contractAddress as ContractAddr, - msg: Buffer.from('{"": {}}'), - funds: [], - }), - ], - onError: (e) => { - if (e.message.includes("contract: ")) { - setContractAddress(""); - setCmds([]); - } else { - const executeCmds: string[] = []; - Array.from(e.message?.matchAll(/`(.*?)`/g) || []) - .slice(1) - .forEach((match) => executeCmds.push(match[1])); - setCmds(executeCmds.map((cmd) => [cmd, `{"${cmd}": {}}`])); - } - }, - }); + useEffect(() => { + if (isEmptyContractAddress) { + setContractAddress(""); + } + setCmds(execCmds); + }, [isEmptyContractAddress, execCmds]); useEffect(() => { (async () => { diff --git a/yarn.lock b/yarn.lock index ff3208fb1..ff4120b00 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2172,6 +2172,16 @@ "@cosmjs/math" "^0.29.3" "@cosmjs/utils" "^0.29.3" +"@cosmjs/amino@^0.29.5": + version "0.29.5" + resolved "https://registry.yarnpkg.com/@cosmjs/amino/-/amino-0.29.5.tgz#053b4739a90b15b9e2b781ccd484faf64bd49aec" + integrity sha512-Qo8jpC0BiziTSUqpkNatBcwtKNhCovUnFul9SlT/74JUCdLYaeG5hxr3q1cssQt++l4LvlcpF+OUXL48XjNjLw== + dependencies: + "@cosmjs/crypto" "^0.29.5" + "@cosmjs/encoding" "^0.29.5" + "@cosmjs/math" "^0.29.5" + "@cosmjs/utils" "^0.29.5" + "@cosmjs/cosmwasm-stargate@^0.29.3": version "0.29.3" resolved "https://registry.yarnpkg.com/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.29.3.tgz#f6279fc6d590db01d6cb0f5cfae43bb2c88c279b" @@ -2220,6 +2230,19 @@ elliptic "^6.5.3" libsodium-wrappers "^0.7.6" +"@cosmjs/crypto@^0.29.5": + version "0.29.5" + resolved "https://registry.yarnpkg.com/@cosmjs/crypto/-/crypto-0.29.5.tgz#ab99fc382b93d8a8db075780cf07487a0f9519fd" + integrity sha512-2bKkaLGictaNL0UipQCL6C1afaisv6k8Wr/GCLx9FqiyFkh9ZgRHDyetD64ZsjnWV/N/D44s/esI+k6oPREaiQ== + dependencies: + "@cosmjs/encoding" "^0.29.5" + "@cosmjs/math" "^0.29.5" + "@cosmjs/utils" "^0.29.5" + "@noble/hashes" "^1" + bn.js "^5.2.0" + elliptic "^6.5.4" + libsodium-wrappers "^0.7.6" + "@cosmjs/encoding@^0.20.0": version "0.20.1" resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.20.1.tgz#1d1162b3eca51b7244cd45102e313612cea77281" @@ -2247,6 +2270,15 @@ bech32 "^1.1.4" readonly-date "^1.0.0" +"@cosmjs/encoding@^0.29.5": + version "0.29.5" + resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.29.5.tgz#009a4b1c596cdfd326f30ccfa79f5e56daa264f2" + integrity sha512-G4rGl/Jg4dMCw5u6PEZHZcoHnUBlukZODHbm/wcL4Uu91fkn5jVo5cXXZcvs4VCkArVGrEj/52eUgTZCmOBGWQ== + dependencies: + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" + "@cosmjs/json-rpc@^0.29.3": version "0.29.3" resolved "https://registry.yarnpkg.com/@cosmjs/json-rpc/-/json-rpc-0.29.3.tgz#17d99b71410c24e082d492d307ad25463d0a72d1" @@ -2288,6 +2320,13 @@ dependencies: bn.js "^5.2.0" +"@cosmjs/math@^0.29.5": + version "0.29.5" + resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.29.5.tgz#722c96e080d6c2b62215ce9f4c70da7625b241b6" + integrity sha512-2GjKcv+A9f86MAWYLUkjhw1/WpRl2R1BTb3m9qPG7lzMA7ioYff9jY5SPCfafKdxM4TIQGxXQlYGewQL16O68Q== + dependencies: + bn.js "^5.2.0" + "@cosmjs/proto-signing@^0.24.0-alpha.25": version "0.24.1" resolved "https://registry.yarnpkg.com/@cosmjs/proto-signing/-/proto-signing-0.24.1.tgz#4ee38d4e0d29c626344fb832235fda8e8d645c28" @@ -2310,6 +2349,19 @@ cosmjs-types "^0.5.2" long "^4.0.0" +"@cosmjs/proto-signing@^0.29.5": + version "0.29.5" + resolved "https://registry.yarnpkg.com/@cosmjs/proto-signing/-/proto-signing-0.29.5.tgz#af3b62a46c2c2f1d2327d678b13b7262db1fe87c" + integrity sha512-QRrS7CiKaoETdgIqvi/7JC2qCwCR7lnWaUsTzh/XfRy3McLkEd+cXbKAW3cygykv7IN0VAEIhZd2lyIfT8KwNA== + dependencies: + "@cosmjs/amino" "^0.29.5" + "@cosmjs/crypto" "^0.29.5" + "@cosmjs/encoding" "^0.29.5" + "@cosmjs/math" "^0.29.5" + "@cosmjs/utils" "^0.29.5" + cosmjs-types "^0.5.2" + long "^4.0.0" + "@cosmjs/socket@^0.29.3": version "0.29.3" resolved "https://registry.yarnpkg.com/@cosmjs/socket/-/socket-0.29.3.tgz#0c3fcf16066946c43a7666516ee0edc096ff977c" @@ -2376,6 +2428,11 @@ resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.29.3.tgz#d7e1f381267e61b7d3219ebd75d46defc397cd43" integrity sha512-UuKoBN2xiRXcBpz7jzCwagKhOnLOsRmR8mu3IzY+Yx38i8rW52FSXMbxC/yE83X0vLea+zgMQFPwv0gy4QWUJw== +"@cosmjs/utils@^0.29.5": + version "0.29.5" + resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.29.5.tgz#3fed1b3528ae8c5f1eb5d29b68755bebfd3294ee" + integrity sha512-m7h+RXDUxOzEOGt4P+3OVPX7PuakZT3GBmaM/Y2u+abN3xZkziykD/NvedYFvvCCdQo714XcGl33bwifS9FZPQ== + "@cosmos-kit/config@^0.16.2": version "0.16.2" resolved "https://registry.yarnpkg.com/@cosmos-kit/config/-/config-0.16.2.tgz#17b3444bd28600286ab30c187ed81fcaf4fd324d" @@ -5787,7 +5844,7 @@ electron-to-chromium@^1.4.202: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.247.tgz#cc93859bc5fc521f611656e65ce17eae26a0fd3d" integrity sha512-FLs6R4FQE+1JHM0hh3sfdxnYjKvJpHZyhQDjc2qFq/xFvmmRt/TATNToZhrcGUFzpF2XjeiuozrA8lI0PZmYYw== -elliptic@^6.4.0, elliptic@^6.5.3: +elliptic@^6.4.0, elliptic@^6.5.3, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== From eee83f6a29673cd879c18f7bed7bb7551e098e76 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 22 Dec 2022 16:33:22 +0700 Subject: [PATCH 02/27] ci: add Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df54d0ff8..5b9130beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#38](https://github.com/alleslabs/celatone-frontend/pull/38) Show execute msgs cmd when wallet is not connected - [#41](https://github.com/alleslabs/celatone-frontend/pull/41) Add Github action for tracking CHANGELOG.md for changes ### Improvements From 7fb812abf7648d4279b82bc7dcf41c1f9584d1e6 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Fri, 23 Dec 2022 11:07:44 +0700 Subject: [PATCH 03/27] fix: executeCmds hook --- src/lib/app-provider/queries/simulateFee.ts | 12 +++++------- src/lib/hooks/useDummyWallet.ts | 5 ++--- src/lib/pages/execute/hook/useExecuteCmds.ts | 10 ++++++++-- src/lib/pages/execute/index.tsx | 17 +++++++---------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/lib/app-provider/queries/simulateFee.ts b/src/lib/app-provider/queries/simulateFee.ts index d6b455f83..7bedd391d 100644 --- a/src/lib/app-provider/queries/simulateFee.ts +++ b/src/lib/app-provider/queries/simulateFee.ts @@ -22,6 +22,8 @@ export const useSimulateFeeQuery = ({ useWallet(); const { dummyWallet, dummyAddress } = useDummyWallet(); + const userAddress = address || dummyAddress || ""; + const simulateFn = async (msgs: ComposedMsg[]) => { let client = await getCosmWasmClient(); if ( @@ -40,19 +42,15 @@ export const useSimulateFeeQuery = ({ ); } - if (!client || !dummyAddress) { + if (!client) { return Promise.resolve(undefined); } - return (await client.simulate( - address || dummyAddress, - msgs, - undefined - )) as Gas; + return (await client.simulate(userAddress, msgs, undefined)) as Gas; }; return useQuery({ - queryKey: ["simulate", currentChainName, address, messages], + queryKey: ["simulate", currentChainName, userAddress, messages], queryFn: async ({ queryKey }) => simulateFn(queryKey[3] as ComposedMsg[]), enabled, keepPreviousData: true, diff --git a/src/lib/hooks/useDummyWallet.ts b/src/lib/hooks/useDummyWallet.ts index 63d95ea9f..17df3fda3 100644 --- a/src/lib/hooks/useDummyWallet.ts +++ b/src/lib/hooks/useDummyWallet.ts @@ -12,9 +12,8 @@ export const useDummyWallet = () => { const getData = async () => { const wallet = await DirectSecp256k1HdWallet.fromMnemonic( DUMMY_MNEMONIC || "", - { - prefix: currentChainRecord?.chain.bech32_prefix, - } + undefined, + currentChainRecord?.chain.bech32_prefix ); setDummyWallet(wallet); diff --git a/src/lib/pages/execute/hook/useExecuteCmds.ts b/src/lib/pages/execute/hook/useExecuteCmds.ts index 2d43273d3..683e12a09 100644 --- a/src/lib/pages/execute/hook/useExecuteCmds.ts +++ b/src/lib/pages/execute/hook/useExecuteCmds.ts @@ -1,11 +1,12 @@ import { useWallet } from "@cosmos-kit/react"; -import { useState } from "react"; +import router from "next/router"; +import { useEffect, useState } from "react"; import { useSimulateFeeQuery } from "lib/app-provider"; import { useDummyWallet } from "lib/hooks"; import type { HumanAddr, ContractAddr } from "lib/types"; import { MsgType } from "lib/types"; -import { composeMsg } from "lib/utils"; +import { composeMsg, getFirstQueryParam } from "lib/utils"; interface UseExecuteCmdsProps { contractAddress: string; @@ -16,6 +17,11 @@ export const useExecuteCmds = ({ contractAddress }: UseExecuteCmdsProps) => { const [execCmds, setExecCmds] = useState<[string, string][]>([]); const { address } = useWallet(); const { dummyAddress } = useDummyWallet(); + const contractAddr = getFirstQueryParam(router.query.contract); + + useEffect(() => { + if (!contractAddr) setExecCmds([]); + }, [contractAddr]); // TODO - Refactor - use useSimulateFee const { isFetching } = useSimulateFeeQuery({ diff --git a/src/lib/pages/execute/index.tsx b/src/lib/pages/execute/index.tsx index 91fa66524..096f9d9b0 100644 --- a/src/lib/pages/execute/index.tsx +++ b/src/lib/pages/execute/index.tsx @@ -30,7 +30,6 @@ const Execute = () => { const [contractAddress, setContractAddress] = useState(""); const [contractName, setContractName] = useState(""); const [initialMsg, setInitialMsg] = useState(""); - const [cmds, setCmds] = useState<[string, string][]>([]); const { isFetching, isEmptyContractAddress, execCmds } = useExecuteCmds({ contractAddress, @@ -60,8 +59,7 @@ const Execute = () => { if (isEmptyContractAddress) { setContractAddress(""); } - setCmds(execCmds); - }, [isEmptyContractAddress, execCmds]); + }, [isEmptyContractAddress]); useEffect(() => { (async () => { @@ -87,7 +85,6 @@ const Execute = () => { setContractAddress(contractAddr); setInitialMsg(jsonMsg); - if (!contractAddr) setCmds([]); })(); }, [router, endpoint, getContractInfo, onContractSelect]); @@ -130,7 +127,11 @@ const Execute = () => { Contract Address - {!notSelected ? ( + {notSelected ? ( + + Not Selected + + ) : ( { textFormat={isMobile ? "truncate" : "normal"} maxWidth="none" /> - ) : ( - - Not Selected - )} @@ -164,7 +161,7 @@ const Execute = () => { ); From d398a9baf2a458262c3b9024b77233a68cf07770 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Fri, 23 Dec 2022 13:41:11 +0700 Subject: [PATCH 04/27] fix: change fromMnemonic parameter --- src/lib/hooks/useDummyWallet.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lib/hooks/useDummyWallet.ts b/src/lib/hooks/useDummyWallet.ts index 17df3fda3..a057f930f 100644 --- a/src/lib/hooks/useDummyWallet.ts +++ b/src/lib/hooks/useDummyWallet.ts @@ -10,16 +10,19 @@ export const useDummyWallet = () => { const [dummyAddress, setDummyAddress] = useState(); useEffect(() => { const getData = async () => { - const wallet = await DirectSecp256k1HdWallet.fromMnemonic( - DUMMY_MNEMONIC || "", - undefined, - currentChainRecord?.chain.bech32_prefix - ); + if (DUMMY_MNEMONIC) { + const wallet = await DirectSecp256k1HdWallet.fromMnemonic( + DUMMY_MNEMONIC, + { + prefix: currentChainRecord?.chain.bech32_prefix, + } + ); - setDummyWallet(wallet); + setDummyWallet(wallet); - const { address } = (await wallet.getAccounts())[0]; - setDummyAddress(address); + const { address } = (await wallet.getAccounts())[0]; + setDummyAddress(address); + } }; getData(); From e0fc08338ca616ee721ed36306ca2a7dbf722ded Mon Sep 17 00:00:00 2001 From: bkioshn Date: Fri, 23 Dec 2022 15:56:05 +0700 Subject: [PATCH 05/27] fix: change environment variable name --- src/env.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env.ts b/src/env.ts index 24e29e7f7..247f7f70f 100644 --- a/src/env.ts +++ b/src/env.ts @@ -55,4 +55,4 @@ export const CELATONE_CONSTANTS: CelatoneConstants = { msgTypeUrl: MSG_TYPE_URL, }; -export const { DUMMY_MNEMONIC } = process.env; +export const DUMMY_MNEMONIC = process.env.NEXT_PUBLIC_DUMMY_MNEMONIC; From a5a7df5964c028c04466c240a0f7071d2b436277 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Fri, 23 Dec 2022 23:09:41 +0700 Subject: [PATCH 06/27] fix: remove unnecessary function, code shortening --- src/lib/app-provider/queries/simulateFee.ts | 7 +------ src/lib/hooks/useDummyWallet.ts | 6 ++---- src/lib/pages/execute/hook/useExecuteCmds.ts | 10 ++-------- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/lib/app-provider/queries/simulateFee.ts b/src/lib/app-provider/queries/simulateFee.ts index 7bedd391d..3c05b06c1 100644 --- a/src/lib/app-provider/queries/simulateFee.ts +++ b/src/lib/app-provider/queries/simulateFee.ts @@ -26,12 +26,7 @@ export const useSimulateFeeQuery = ({ const simulateFn = async (msgs: ComposedMsg[]) => { let client = await getCosmWasmClient(); - if ( - !currentChainRecord || - !currentChainRecord.preferredEndpoints || - !currentChainRecord.preferredEndpoints.rpc || - !currentChainRecord.preferredEndpoints.rpc[0] - ) { + if (!currentChainRecord?.preferredEndpoints?.rpc?.[0]) { return Promise.resolve(undefined); } diff --git a/src/lib/hooks/useDummyWallet.ts b/src/lib/hooks/useDummyWallet.ts index a057f930f..74f95f5b8 100644 --- a/src/lib/hooks/useDummyWallet.ts +++ b/src/lib/hooks/useDummyWallet.ts @@ -9,7 +9,7 @@ export const useDummyWallet = () => { const [dummyWallet, setDummyWallet] = useState(); const [dummyAddress, setDummyAddress] = useState(); useEffect(() => { - const getData = async () => { + (async () => { if (DUMMY_MNEMONIC) { const wallet = await DirectSecp256k1HdWallet.fromMnemonic( DUMMY_MNEMONIC, @@ -23,9 +23,7 @@ export const useDummyWallet = () => { const { address } = (await wallet.getAccounts())[0]; setDummyAddress(address); } - }; - - getData(); + })(); }, [currentChainRecord?.chain.bech32_prefix]); return { dummyWallet, dummyAddress }; diff --git a/src/lib/pages/execute/hook/useExecuteCmds.ts b/src/lib/pages/execute/hook/useExecuteCmds.ts index 683e12a09..2d43273d3 100644 --- a/src/lib/pages/execute/hook/useExecuteCmds.ts +++ b/src/lib/pages/execute/hook/useExecuteCmds.ts @@ -1,12 +1,11 @@ import { useWallet } from "@cosmos-kit/react"; -import router from "next/router"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useSimulateFeeQuery } from "lib/app-provider"; import { useDummyWallet } from "lib/hooks"; import type { HumanAddr, ContractAddr } from "lib/types"; import { MsgType } from "lib/types"; -import { composeMsg, getFirstQueryParam } from "lib/utils"; +import { composeMsg } from "lib/utils"; interface UseExecuteCmdsProps { contractAddress: string; @@ -17,11 +16,6 @@ export const useExecuteCmds = ({ contractAddress }: UseExecuteCmdsProps) => { const [execCmds, setExecCmds] = useState<[string, string][]>([]); const { address } = useWallet(); const { dummyAddress } = useDummyWallet(); - const contractAddr = getFirstQueryParam(router.query.contract); - - useEffect(() => { - if (!contractAddr) setExecCmds([]); - }, [contractAddr]); // TODO - Refactor - use useSimulateFee const { isFetching } = useSimulateFeeQuery({ From 63d5158984b7e97d41a774ed5549fd4de5ad9cc8 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Sat, 24 Dec 2022 11:22:21 +0700 Subject: [PATCH 07/27] feat: render query command shortcut in contract details page --- src/lib/app-provider/queries/useQueryCmds.ts | 35 +++++++++++++ .../components/CommandSection.tsx | 51 ++++++++++++++++++- 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/lib/app-provider/queries/useQueryCmds.ts diff --git a/src/lib/app-provider/queries/useQueryCmds.ts b/src/lib/app-provider/queries/useQueryCmds.ts new file mode 100644 index 000000000..5078f938a --- /dev/null +++ b/src/lib/app-provider/queries/useQueryCmds.ts @@ -0,0 +1,35 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { useState } from "react"; + +import { useEndpoint } from "lib/hooks"; +import { queryData } from "lib/services/contract"; +import type { ContractAddr, RpcQueryError } from "lib/types"; + +interface UseQueryCmdsProps { + contractAddress: string; +} +export const useQueryCmds = ({ contractAddress }: UseQueryCmdsProps) => { + const [queryCmds, setQueryCmds] = useState<[string, string][]>([]); + const endpoint = useEndpoint(); + + const { isFetching } = useQuery( + ["query", "cmds", endpoint, contractAddress, '{"": {}}'], + async () => + queryData(endpoint, contractAddress as ContractAddr, '{"": {}}'), + { + enabled: !!contractAddress, + retry: false, + cacheTime: 0, + refetchOnWindowFocus: false, + onError: (e: AxiosError) => { + const cmds: string[] = []; + Array.from(e.response?.data.message?.matchAll(/`(.*?)`/g) || []) + .slice(1) + .forEach((match) => cmds.push(match[1])); + setQueryCmds(cmds.map((cmd) => [cmd, `{"${cmd}": {}}`])); + }, + } + ); + return { isFetching, queryCmds }; +}; diff --git a/src/lib/pages/contract-details/components/CommandSection.tsx b/src/lib/pages/contract-details/components/CommandSection.tsx index c5aa00384..62b00c6f3 100644 --- a/src/lib/pages/contract-details/components/CommandSection.tsx +++ b/src/lib/pages/contract-details/components/CommandSection.tsx @@ -1,4 +1,10 @@ -import { Flex, Text } from "@chakra-ui/react"; +import { ButtonGroup, Flex, Spinner, Text } from "@chakra-ui/react"; +import router from "next/router"; +import { useState } from "react"; + +import { useQueryCmds } from "lib/app-provider/queries/useQueryCmds"; +import ContractCmdButton from "lib/components/ContractCmdButton"; +import { getFirstQueryParam, jsonPrettify } from "lib/utils"; export const CommandSection = () => { /** @@ -6,6 +12,48 @@ export const CommandSection = () => { * - Make an interface * - Wireup with real query/execute commands data */ + const contractAddress = getFirstQueryParam(router.query.contractAddress); + + const [, setQueryMsg] = useState(""); + + const { isFetching: isQueryCmdsFetching, queryCmds } = useQueryCmds({ + contractAddress, + }); + + const renderQueryCmds = () => { + if (isQueryCmdsFetching) { + return ; + } + if (queryCmds.length) { + return ( + button": { + marginInlineStart: "0 !important", + marginInlineEnd: "1", + }, + }} + > + {queryCmds.map(([cmd, queryMsg]) => ( + + ))} + + ); + } + return ( + + No messages available + + ); + }; return ( { Query Shortcuts {/* Query Contract Commands */} + {renderQueryCmds()} Date: Mon, 26 Dec 2022 11:53:23 +0700 Subject: [PATCH 08/27] fix: remove setEmptyContractAddress --- src/lib/pages/execute/hook/useExecuteCmds.ts | 5 +---- src/lib/pages/execute/index.tsx | 8 +------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/lib/pages/execute/hook/useExecuteCmds.ts b/src/lib/pages/execute/hook/useExecuteCmds.ts index 2d43273d3..ba1d935dc 100644 --- a/src/lib/pages/execute/hook/useExecuteCmds.ts +++ b/src/lib/pages/execute/hook/useExecuteCmds.ts @@ -11,8 +11,6 @@ interface UseExecuteCmdsProps { contractAddress: string; } export const useExecuteCmds = ({ contractAddress }: UseExecuteCmdsProps) => { - const [isEmptyContractAddress, setIsEmptyContractAddress] = - useState(false); const [execCmds, setExecCmds] = useState<[string, string][]>([]); const { address } = useWallet(); const { dummyAddress } = useDummyWallet(); @@ -30,7 +28,6 @@ export const useExecuteCmds = ({ contractAddress }: UseExecuteCmdsProps) => { ], onError: (e) => { if (e.message.includes("contract: ")) { - setIsEmptyContractAddress(true); setExecCmds([]); } else { const executeCmds: string[] = []; @@ -41,5 +38,5 @@ export const useExecuteCmds = ({ contractAddress }: UseExecuteCmdsProps) => { } }, }); - return { isFetching, isEmptyContractAddress, execCmds }; + return { isFetching, execCmds }; }; diff --git a/src/lib/pages/execute/index.tsx b/src/lib/pages/execute/index.tsx index 096f9d9b0..3b99bb2f9 100644 --- a/src/lib/pages/execute/index.tsx +++ b/src/lib/pages/execute/index.tsx @@ -31,7 +31,7 @@ const Execute = () => { const [contractName, setContractName] = useState(""); const [initialMsg, setInitialMsg] = useState(""); - const { isFetching, isEmptyContractAddress, execCmds } = useExecuteCmds({ + const { isFetching, execCmds } = useExecuteCmds({ contractAddress, }); @@ -55,12 +55,6 @@ const Execute = () => { [router] ); - useEffect(() => { - if (isEmptyContractAddress) { - setContractAddress(""); - } - }, [isEmptyContractAddress]); - useEffect(() => { (async () => { const contractAddr = getFirstQueryParam(router.query.contract); From 7fc69155da2f891602e624578c9a4671da730b1b Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 26 Dec 2022 13:00:28 +0700 Subject: [PATCH 09/27] fix: navigate to query page when click on query command button --- src/lib/components/ContractCmdButton.tsx | 7 +++--- .../components/CommandSection.tsx | 24 ++++++++++++------- .../pages/execute/components/ExecuteArea.tsx | 3 +-- src/lib/pages/query/components/QueryArea.tsx | 3 +-- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/lib/components/ContractCmdButton.tsx b/src/lib/components/ContractCmdButton.tsx index b6c7b3e7d..12fc54356 100644 --- a/src/lib/components/ContractCmdButton.tsx +++ b/src/lib/components/ContractCmdButton.tsx @@ -2,10 +2,9 @@ import { Button } from "@chakra-ui/react"; interface ContractCmdButtonProps { cmd: string; - msg: string; - setMsg: (msg: string) => void; + onClickCmd: () => void; } -const ContractCmdButton = ({ cmd, msg, setMsg }: ContractCmdButtonProps) => { +const ContractCmdButton = ({ cmd, onClickCmd }: ContractCmdButtonProps) => { return ( - - - )} - - + + + + + + ); }; diff --git a/src/lib/pages/instantiate/completed.tsx b/src/lib/pages/instantiate/completed.tsx index 47762054a..4cc6fa3be 100644 --- a/src/lib/pages/instantiate/completed.tsx +++ b/src/lib/pages/instantiate/completed.tsx @@ -4,10 +4,10 @@ import { useRouter } from "next/router"; import { MdCheckCircle } from "react-icons/md"; import { ExplorerLink } from "lib/components/ExplorerLink"; -import { InstantiateOffChainDetail } from "lib/components/InstantiateOffchainDetail"; import { TxReceiptRender } from "lib/components/tx/receipt"; import WasmPageContainer from "lib/components/WasmPageContainer"; import { getExplorerContractAddressUrl } from "lib/data"; +import { InstantiateOffChainForm } from "lib/pages/instantiate/component/InstantiateOffchainForm"; import type { ContractAddr } from "lib/types"; import { formatUFee } from "lib/utils"; @@ -104,7 +104,7 @@ const Completed = ({ txInfo }: CompletedProps) => { {/* Off chain detail */} - { const { address = "" } = useWallet(); const router = useRouter(); - const { updateContractInfo, getAllTags } = useContractStore(); + const { updateContractInfo } = useContractStore(); const userKey = useUserKey(); const { @@ -46,20 +38,28 @@ export const InstantiateOffChainDetail = observer( watch, handleSubmit, formState: { errors }, - } = useForm({ + } = useForm({ defaultValues: { name: "", description: "", - tags: [] as string[], - contractLists: [] as Option[], + tags: [], + lists: [], }, mode: "all", }); - const nameState = watch("name"); - const descriptionState = watch("description"); - const tagsState = watch("tags"); - const contractListState = watch("contractLists"); + const offchainState: OffchainDetail = { + name: watch("name"), + description: watch("description"), + tags: watch("tags"), + lists: watch("lists"), + }; + const setTagsValue = (selectedOptions: string[]) => { + setValue("tags", selectedOptions); + }; + const setContractListsValue = (selectedOptions: Option[]) => { + setValue("lists", selectedOptions); + }; const saveContract = () => { handleSubmit((data) => { @@ -72,7 +72,7 @@ export const InstantiateOffChainDetail = observer( data.name, data.description, data.tags, - data.contractLists + data.lists ); router.push("/contract-list/instantiated-by-me"); })(); @@ -90,50 +90,14 @@ export const InstantiateOffChainDetail = observer( )} - - - { - setValue("tags", selectedOptions); - }} - labelBgColor="background.main" - /> - { - setValue("contractLists", selectedOptions); - }} - labelBgColor="background.main" + setTagsValue={setTagsValue} + setContractListsValue={setContractListsValue} + errors={errors} /> {cta && ( From ea4b4853f52894f13973a0db6235da4b8b827ed8 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 27 Dec 2022 11:27:03 +0700 Subject: [PATCH 13/27] chore: format code --- src/lib/app-provider/index.ts | 1 + src/lib/app-provider/queries/index.ts | 1 + src/lib/components/ContractCmdButton.tsx | 4 +--- src/lib/pages/contract-details/components/CommandSection.tsx | 2 +- src/lib/utils/router.ts | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib/app-provider/index.ts b/src/lib/app-provider/index.ts index 08198e52c..62c83435a 100644 --- a/src/lib/app-provider/index.ts +++ b/src/lib/app-provider/index.ts @@ -1,3 +1,4 @@ export * from "./hooks"; export * from "./tx"; export * from "./contexts"; +export * from "./queries"; diff --git a/src/lib/app-provider/queries/index.ts b/src/lib/app-provider/queries/index.ts index 8b9f9d20c..b9b4211b0 100644 --- a/src/lib/app-provider/queries/index.ts +++ b/src/lib/app-provider/queries/index.ts @@ -1 +1,2 @@ export * from "./simulateFee"; +export * from "./useQueryCmds"; diff --git a/src/lib/components/ContractCmdButton.tsx b/src/lib/components/ContractCmdButton.tsx index 12fc54356..a59fa6e66 100644 --- a/src/lib/components/ContractCmdButton.tsx +++ b/src/lib/components/ContractCmdButton.tsx @@ -15,9 +15,7 @@ const ContractCmdButton = ({ cmd, onClickCmd }: ContractCmdButtonProps) => { borderColor="rgba(255, 255, 255, 0.3)" borderRadius="16px" fontWeight="400" - onClick={() => { - onClickCmd(); - }} + onClick={onClickCmd} > {cmd} diff --git a/src/lib/pages/contract-details/components/CommandSection.tsx b/src/lib/pages/contract-details/components/CommandSection.tsx index 7268a88aa..39b29f786 100644 --- a/src/lib/pages/contract-details/components/CommandSection.tsx +++ b/src/lib/pages/contract-details/components/CommandSection.tsx @@ -1,7 +1,7 @@ import { ButtonGroup, Flex, Spinner, Text } from "@chakra-ui/react"; import router from "next/router"; -import { useQueryCmds } from "lib/app-provider/queries/useQueryCmds"; +import { useQueryCmds } from "lib/app-provider"; import ContractCmdButton from "lib/components/ContractCmdButton"; import { encode, getFirstQueryParam, jsonPrettify } from "lib/utils"; diff --git a/src/lib/utils/router.ts b/src/lib/utils/router.ts index 46aa97868..fa719a833 100644 --- a/src/lib/utils/router.ts +++ b/src/lib/utils/router.ts @@ -1,3 +1,4 @@ +// TODO - Should return undefined export const getFirstQueryParam = (param: string | string[] | undefined) => { if (typeof param === "string") { return param; From 9d4a2aa367b99db184facc24a6e7ffda90fa27af Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 27 Dec 2022 11:31:02 +0700 Subject: [PATCH 14/27] fix: form color --- CHANGELOG.md | 2 ++ src/lib/components/modal/contract/EditContract.tsx | 1 + .../components/modal/contract/SaveNewContract.tsx | 12 ++++++++---- src/lib/components/offchain/OffChainForm.tsx | 6 ++++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6034b701..ed6e31f77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#50](https://github.com/alleslabs/celatone-frontend/pull/50) Refactor OffChain component to use react-form and remove redundant offchain components + ### Bug fixes - [#45](https://github.com/alleslabs/celatone-frontend/pull/45) Add chain ID and code details to contract detail data loader diff --git a/src/lib/components/modal/contract/EditContract.tsx b/src/lib/components/modal/contract/EditContract.tsx index b27291d90..33610a11b 100644 --- a/src/lib/components/modal/contract/EditContract.tsx +++ b/src/lib/components/modal/contract/EditContract.tsx @@ -91,6 +91,7 @@ export const EditContract = ({ contractInfo, menuItemProps }: ModalProps) => { setTagsValue={setTagsValue} setContractListsValue={setContractListsValue} errors={errors} + labelBgColor="gray.800" /> ); diff --git a/src/lib/components/modal/contract/SaveNewContract.tsx b/src/lib/components/modal/contract/SaveNewContract.tsx index 6ef0ac269..4976889df 100644 --- a/src/lib/components/modal/contract/SaveNewContract.tsx +++ b/src/lib/components/modal/contract/SaveNewContract.tsx @@ -102,14 +102,15 @@ export function SaveNewContract({ list, buttonProps }: SaveNewContractProps) { onSuccess(data) { const contractInfo = getContractInfo(contractAddressState); reset({ + contractAddress: contractAddressState, instantiator: data.instantiator, label: data.label, created: data.createdTime, name: contractInfo?.name ?? data.label, - description: contractInfo?.description, - tags: contractInfo?.tags, + description: contractInfo?.description ?? "", + tags: contractInfo?.tags ?? [], lists: [ - list, + ...initialList, ...(contractInfo?.lists ?? []).filter( (item) => item.value !== list.value ), @@ -173,7 +174,7 @@ export function SaveNewContract({ list, buttonProps }: SaveNewContractProps) { status.state !== "success" || !!errors.name || !!errors.description } otherBtnTitle="Cancel" - otherAction={reset} + otherAction={resetForm} > diff --git a/src/lib/components/offchain/OffChainForm.tsx b/src/lib/components/offchain/OffChainForm.tsx index 66e374cfb..4b23ae458 100644 --- a/src/lib/components/offchain/OffChainForm.tsx +++ b/src/lib/components/offchain/OffChainForm.tsx @@ -31,6 +31,7 @@ interface OffChainFormProps { setTagsValue: (options: string[]) => void; setContractListsValue: (options: Option[]) => void; errors: Partial>; + labelBgColor?: string; } export const OffChainForm = ({ @@ -41,6 +42,7 @@ export const OffChainForm = ({ setTagsValue, setContractListsValue, errors, + labelBgColor = "background.main", }: OffChainFormProps) => { const userKey = useUserKey(); const { getAllTags } = useContractStore(); @@ -57,6 +59,7 @@ export const OffChainForm = ({ maxLength: MAX_CONTRACT_NAME_LENGTH, }} error={errors.name && getMaxContractNameLengthError(state.name.length)} + labelBgColor={labelBgColor} /> ({ errors.description && getMaxContractDescriptionLengthError(state.description.length) } + labelBgColor={labelBgColor} /> ({ placeholder="Tags" helperText="Add tag to organize and manage your contracts" setResult={setTagsValue} + labelBgColor={labelBgColor} /> ({ helperText="Grouping your contracts by adding to your existing list or create a new list" setResult={setContractListsValue} + labelBgColor={labelBgColor} /> ); From a233ef82eb89dc2b7e1175d937b813c8b048a794 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 27 Dec 2022 13:15:59 +0700 Subject: [PATCH 15/27] fix: tag selection --- src/lib/components/forms/TagSelection.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/lib/components/forms/TagSelection.tsx b/src/lib/components/forms/TagSelection.tsx index c6d4ecaae..44526f220 100644 --- a/src/lib/components/forms/TagSelection.tsx +++ b/src/lib/components/forms/TagSelection.tsx @@ -15,7 +15,7 @@ import { } from "@chakra-ui/react"; import { matchSorter } from "match-sorter"; import type { CSSProperties, KeyboardEvent } from "react"; -import { useEffect, useState, useRef, forwardRef } from "react"; +import { useState, useRef, forwardRef } from "react"; import { MdCheckCircle, MdClose } from "react-icons/md"; import mergeRefs from "lib/utils/mergeRefs"; @@ -69,7 +69,7 @@ export const TagSelection = forwardRef( // TODO: refactor to reduce complexity // eslint-disable-next-line sonarjs/cognitive-complexity ) => { - const [optionsCopy, setOptionsCopy] = useState([]); + const [optionsCopy, setOptionsCopy] = useState(options); const [partialResult, setPartialResult] = useState([]); const [displayOptions, setDisplayOptions] = useState(false); const [inputValue, setInputValue] = useState(""); @@ -129,10 +129,6 @@ export const TagSelection = forwardRef( handler: () => setDisplayOptions(false), }); - useEffect(() => { - setOptionsCopy(options); - }, [options]); - return ( From 7a22c016848dcab557d5523004836483b7cb9fef Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 27 Dec 2022 13:30:33 +0700 Subject: [PATCH 16/27] chore: fix type, value, condition, and typo --- CHANGELOG.md | 2 +- src/lib/app-provider/queries/simulateFee.ts | 4 ++-- src/lib/hooks/useDummyWallet.ts | 5 +++-- src/lib/pages/execute/hook/useExecuteCmds.ts | 5 ++++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90b8d9183..7124e77b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- [#38](https://github.com/alleslabs/celatone-frontend/pull/38) Show execute msgs cmd when wallet is not connected +- [#38](https://github.com/alleslabs/celatone-frontend/pull/38) Show execute msg cmds when wallet is not connected - [#37](https://github.com/alleslabs/celatone-frontend/pull/37) Add contract details data loader - [#31](https://github.com/alleslabs/celatone-frontend/pull/31) Add contract details page ui skeleton - [#41](https://github.com/alleslabs/celatone-frontend/pull/41) Add Github action for tracking CHANGELOG.md for changes diff --git a/src/lib/app-provider/queries/simulateFee.ts b/src/lib/app-provider/queries/simulateFee.ts index 3c05b06c1..df04ae2a4 100644 --- a/src/lib/app-provider/queries/simulateFee.ts +++ b/src/lib/app-provider/queries/simulateFee.ts @@ -22,11 +22,11 @@ export const useSimulateFeeQuery = ({ useWallet(); const { dummyWallet, dummyAddress } = useDummyWallet(); - const userAddress = address || dummyAddress || ""; + const userAddress = address || dummyAddress; const simulateFn = async (msgs: ComposedMsg[]) => { let client = await getCosmWasmClient(); - if (!currentChainRecord?.preferredEndpoints?.rpc?.[0]) { + if (!currentChainRecord?.preferredEndpoints?.rpc?.[0] || !userAddress) { return Promise.resolve(undefined); } diff --git a/src/lib/hooks/useDummyWallet.ts b/src/lib/hooks/useDummyWallet.ts index 74f95f5b8..12553ecae 100644 --- a/src/lib/hooks/useDummyWallet.ts +++ b/src/lib/hooks/useDummyWallet.ts @@ -3,11 +3,12 @@ import { useWallet } from "@cosmos-kit/react"; import { useEffect, useState } from "react"; import { DUMMY_MNEMONIC } from "env"; +import type { HumanAddr } from "lib/types"; export const useDummyWallet = () => { const { currentChainRecord } = useWallet(); const [dummyWallet, setDummyWallet] = useState(); - const [dummyAddress, setDummyAddress] = useState(); + const [dummyAddress, setDummyAddress] = useState(); useEffect(() => { (async () => { if (DUMMY_MNEMONIC) { @@ -21,7 +22,7 @@ export const useDummyWallet = () => { setDummyWallet(wallet); const { address } = (await wallet.getAccounts())[0]; - setDummyAddress(address); + setDummyAddress(address as HumanAddr); } })(); }, [currentChainRecord?.chain.bech32_prefix]); diff --git a/src/lib/pages/execute/hook/useExecuteCmds.ts b/src/lib/pages/execute/hook/useExecuteCmds.ts index e6e15d670..350eb903b 100644 --- a/src/lib/pages/execute/hook/useExecuteCmds.ts +++ b/src/lib/pages/execute/hook/useExecuteCmds.ts @@ -10,13 +10,16 @@ import { composeMsg } from "lib/utils"; interface UseExecuteCmdsProps { contractAddress: string; } + export const useExecuteCmds = ({ contractAddress }: UseExecuteCmdsProps) => { const [execCmds, setExecCmds] = useState<[string, string][]>([]); const { address } = useWallet(); const { dummyAddress } = useDummyWallet(); + const userAddress = address || dummyAddress; + const { isFetching } = useSimulateFeeQuery({ - enabled: !!contractAddress, + enabled: !!contractAddress && !!userAddress, messages: [ composeMsg(MsgType.EXECUTE, { sender: (address || dummyAddress) as HumanAddr, From f46da17b3f8b6a4a58610ed98e59c4e47e2f7789 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 27 Dec 2022 13:36:10 +0700 Subject: [PATCH 17/27] fix: change promise undefined to undefined --- src/lib/app-provider/hooks/useSimulateFee.ts | 2 +- src/lib/app-provider/queries/simulateFee.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/app-provider/hooks/useSimulateFee.ts b/src/lib/app-provider/hooks/useSimulateFee.ts index eeac96854..f8cb3e918 100644 --- a/src/lib/app-provider/hooks/useSimulateFee.ts +++ b/src/lib/app-provider/hooks/useSimulateFee.ts @@ -16,7 +16,7 @@ export const useSimulateFee = () => { const client = await getCosmWasmClient(); if (!client || !address) { setLoading(false); - return Promise.resolve(undefined); + return undefined; } try { const fee = (await client.simulate(address, messages, memo)) as Gas; diff --git a/src/lib/app-provider/queries/simulateFee.ts b/src/lib/app-provider/queries/simulateFee.ts index df04ae2a4..b47adaa28 100644 --- a/src/lib/app-provider/queries/simulateFee.ts +++ b/src/lib/app-provider/queries/simulateFee.ts @@ -27,7 +27,7 @@ export const useSimulateFeeQuery = ({ const simulateFn = async (msgs: ComposedMsg[]) => { let client = await getCosmWasmClient(); if (!currentChainRecord?.preferredEndpoints?.rpc?.[0] || !userAddress) { - return Promise.resolve(undefined); + return undefined; } if (!client && !address && dummyWallet) { @@ -38,7 +38,7 @@ export const useSimulateFeeQuery = ({ } if (!client) { - return Promise.resolve(undefined); + return undefined; } return (await client.simulate(userAddress, msgs, undefined)) as Gas; From b7317fa7651d07e71a376594ba5a14c78d09ad37 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 27 Dec 2022 15:52:44 +0700 Subject: [PATCH 18/27] chore: add changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a3d3007f..2b1f84560 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Features - +- [#44](https://github.com/alleslabs/celatone-frontend/pull/44) Render query cmds shortcut in contract detail page - [#37](https://github.com/alleslabs/celatone-frontend/pull/37) Add contract details data loader - [#31](https://github.com/alleslabs/celatone-frontend/pull/31) Add contract details page ui skeleton - [#41](https://github.com/alleslabs/celatone-frontend/pull/41) Add Github action for tracking CHANGELOG.md for changes From ae22880bb1d108180a42d0b3fcdb7b8978839bcf Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 27 Dec 2022 16:45:55 +0700 Subject: [PATCH 19/27] fix: remove default export --- src/lib/components/ContractCmdButton.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/components/ContractCmdButton.tsx b/src/lib/components/ContractCmdButton.tsx index a59fa6e66..e86b3de86 100644 --- a/src/lib/components/ContractCmdButton.tsx +++ b/src/lib/components/ContractCmdButton.tsx @@ -4,7 +4,10 @@ interface ContractCmdButtonProps { cmd: string; onClickCmd: () => void; } -const ContractCmdButton = ({ cmd, onClickCmd }: ContractCmdButtonProps) => { +export const ContractCmdButton = ({ + cmd, + onClickCmd, +}: ContractCmdButtonProps) => { return ( ); }; - -export default ContractCmdButton; From 496f91e8e1ae39ef958154b48a7a40e607fa3465 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 27 Dec 2022 16:48:38 +0700 Subject: [PATCH 20/27] fix: fix import --- src/lib/pages/contract-details/components/CommandSection.tsx | 2 +- src/lib/pages/execute/components/ExecuteArea.tsx | 2 +- src/lib/pages/query/components/QueryArea.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/pages/contract-details/components/CommandSection.tsx b/src/lib/pages/contract-details/components/CommandSection.tsx index 39b29f786..72b2f9bdf 100644 --- a/src/lib/pages/contract-details/components/CommandSection.tsx +++ b/src/lib/pages/contract-details/components/CommandSection.tsx @@ -2,7 +2,7 @@ import { ButtonGroup, Flex, Spinner, Text } from "@chakra-ui/react"; import router from "next/router"; import { useQueryCmds } from "lib/app-provider"; -import ContractCmdButton from "lib/components/ContractCmdButton"; +import { ContractCmdButton } from "lib/components/ContractCmdButton"; import { encode, getFirstQueryParam, jsonPrettify } from "lib/utils"; export const CommandSection = () => { diff --git a/src/lib/pages/execute/components/ExecuteArea.tsx b/src/lib/pages/execute/components/ExecuteArea.tsx index 8e4df3ebb..667562222 100644 --- a/src/lib/pages/execute/components/ExecuteArea.tsx +++ b/src/lib/pages/execute/components/ExecuteArea.tsx @@ -8,7 +8,7 @@ import { MdInput } from "react-icons/md"; import { useFabricateFee } from "lib/app-provider"; import { useSimulateFeeQuery } from "lib/app-provider/queries"; import { useExecuteContractTx } from "lib/app-provider/tx/execute"; -import ContractCmdButton from "lib/components/ContractCmdButton"; +import { ContractCmdButton } from "lib/components/ContractCmdButton"; import CopyButton from "lib/components/CopyButton"; import { EstimatedFeeRender } from "lib/components/EstimatedFeeRender"; import JsonInput from "lib/components/json/JsonInput"; diff --git a/src/lib/pages/query/components/QueryArea.tsx b/src/lib/pages/query/components/QueryArea.tsx index 3ba80d809..f6efe3929 100644 --- a/src/lib/pages/query/components/QueryArea.tsx +++ b/src/lib/pages/query/components/QueryArea.tsx @@ -5,7 +5,7 @@ import { useQuery } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { useEffect, useState } from "react"; -import ContractCmdButton from "lib/components/ContractCmdButton"; +import { ContractCmdButton } from "lib/components/ContractCmdButton"; import CopyButton from "lib/components/CopyButton"; import JsonInput from "lib/components/json/JsonInput"; import { DEFAULT_RPC_ERROR } from "lib/data"; From ce1b4bdd00819b5ca1ce4dd7d18f897a1d54b3e3 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 28 Dec 2022 13:50:58 +0700 Subject: [PATCH 21/27] chore: move file, change contract address type --- src/lib/app-provider/hooks/index.ts | 1 + src/lib/app-provider/{queries => hooks}/useQueryCmds.ts | 2 +- src/lib/app-provider/queries/index.ts | 1 - src/lib/pages/contract-details/components/CommandSection.tsx | 5 ++++- 4 files changed, 6 insertions(+), 3 deletions(-) rename src/lib/app-provider/{queries => hooks}/useQueryCmds.ts (97%) diff --git a/src/lib/app-provider/hooks/index.ts b/src/lib/app-provider/hooks/index.ts index 1e4b19f02..aadbf6303 100644 --- a/src/lib/app-provider/hooks/index.ts +++ b/src/lib/app-provider/hooks/index.ts @@ -2,3 +2,4 @@ export * from "./useFabricateFee"; export * from "./useSimulateFee"; export * from "./useRestrictedInput"; export * from "./useCelatoneApp"; +export * from "./useQueryCmds"; diff --git a/src/lib/app-provider/queries/useQueryCmds.ts b/src/lib/app-provider/hooks/useQueryCmds.ts similarity index 97% rename from src/lib/app-provider/queries/useQueryCmds.ts rename to src/lib/app-provider/hooks/useQueryCmds.ts index 5078f938a..8f0129772 100644 --- a/src/lib/app-provider/queries/useQueryCmds.ts +++ b/src/lib/app-provider/hooks/useQueryCmds.ts @@ -7,7 +7,7 @@ import { queryData } from "lib/services/contract"; import type { ContractAddr, RpcQueryError } from "lib/types"; interface UseQueryCmdsProps { - contractAddress: string; + contractAddress: ContractAddr; } export const useQueryCmds = ({ contractAddress }: UseQueryCmdsProps) => { const [queryCmds, setQueryCmds] = useState<[string, string][]>([]); diff --git a/src/lib/app-provider/queries/index.ts b/src/lib/app-provider/queries/index.ts index b9b4211b0..8b9f9d20c 100644 --- a/src/lib/app-provider/queries/index.ts +++ b/src/lib/app-provider/queries/index.ts @@ -1,2 +1 @@ export * from "./simulateFee"; -export * from "./useQueryCmds"; diff --git a/src/lib/pages/contract-details/components/CommandSection.tsx b/src/lib/pages/contract-details/components/CommandSection.tsx index 72b2f9bdf..9e8ba8697 100644 --- a/src/lib/pages/contract-details/components/CommandSection.tsx +++ b/src/lib/pages/contract-details/components/CommandSection.tsx @@ -3,6 +3,7 @@ import router from "next/router"; import { useQueryCmds } from "lib/app-provider"; import { ContractCmdButton } from "lib/components/ContractCmdButton"; +import type { ContractAddr } from "lib/types"; import { encode, getFirstQueryParam, jsonPrettify } from "lib/utils"; export const CommandSection = () => { @@ -11,7 +12,9 @@ export const CommandSection = () => { * - Make an interface * - Wireup with real execute commands data */ - const contractAddress = getFirstQueryParam(router.query.contractAddress); + const contractAddress = getFirstQueryParam( + router.query.contractAddress + ) as ContractAddr; const { isFetching: isQueryCmdsFetching, queryCmds } = useQueryCmds({ contractAddress, From 22f57fe5ac549a3f34e6d59c2f99732bfd824246 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 28 Dec 2022 14:14:30 +0700 Subject: [PATCH 22/27] fix: as commented --- CHANGELOG.md | 2 +- src/lib/components/{offchain => }/OffChainForm.tsx | 0 src/lib/components/modal/contract/EditContract.tsx | 4 ++-- src/lib/components/modal/contract/SaveNewContract.tsx | 4 ++-- .../pages/instantiate/component/InstantiateOffchainForm.tsx | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) rename src/lib/components/{offchain => }/OffChainForm.tsx (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed6e31f77..db1298e74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements -- [#50](https://github.com/alleslabs/celatone-frontend/pull/50) Refactor OffChain component to use react-form and remove redundant offchain components +- [#50](https://github.com/alleslabs/celatone-frontend/pull/50) Refactor offchain component to use react-form and remove redundant offchain components ### Bug fixes diff --git a/src/lib/components/offchain/OffChainForm.tsx b/src/lib/components/OffChainForm.tsx similarity index 100% rename from src/lib/components/offchain/OffChainForm.tsx rename to src/lib/components/OffChainForm.tsx diff --git a/src/lib/components/modal/contract/EditContract.tsx b/src/lib/components/modal/contract/EditContract.tsx index 33610a11b..048af9b7a 100644 --- a/src/lib/components/modal/contract/EditContract.tsx +++ b/src/lib/components/modal/contract/EditContract.tsx @@ -4,8 +4,8 @@ import { useForm } from "react-hook-form"; import { ExplorerLink } from "lib/components/ExplorerLink"; import { ActionModal } from "lib/components/modal/ActionModal"; -import type { OffchainDetail } from "lib/components/offchain/OffChainForm"; -import { OffChainForm } from "lib/components/offchain/OffChainForm"; +import type { OffchainDetail } from "lib/components/OffChainForm"; +import { OffChainForm } from "lib/components/OffChainForm"; import { useHandleContractSave } from "lib/hooks/useHandleSave"; import type { ContractInfo } from "lib/stores/contract"; import type { Option } from "lib/types"; diff --git a/src/lib/components/modal/contract/SaveNewContract.tsx b/src/lib/components/modal/contract/SaveNewContract.tsx index 4976889df..47679ee7c 100644 --- a/src/lib/components/modal/contract/SaveNewContract.tsx +++ b/src/lib/components/modal/contract/SaveNewContract.tsx @@ -10,8 +10,8 @@ import { useCelatoneApp } from "lib/app-provider"; import type { FormStatus } from "lib/components/forms"; import { ControllerInput } from "lib/components/forms"; import { ActionModal } from "lib/components/modal/ActionModal"; -import type { OffchainDetail } from "lib/components/offchain/OffChainForm"; -import { OffChainForm } from "lib/components/offchain/OffChainForm"; +import type { OffchainDetail } from "lib/components/OffChainForm"; +import { OffChainForm } from "lib/components/OffChainForm"; import { DEFAULT_RPC_ERROR, INSTANTIATED_LIST_NAME } from "lib/data"; import { useContractStore, useEndpoint } from "lib/hooks"; import { useHandleContractSave } from "lib/hooks/useHandleSave"; diff --git a/src/lib/pages/instantiate/component/InstantiateOffchainForm.tsx b/src/lib/pages/instantiate/component/InstantiateOffchainForm.tsx index b06652ec1..d11d9e3b1 100644 --- a/src/lib/pages/instantiate/component/InstantiateOffchainForm.tsx +++ b/src/lib/pages/instantiate/component/InstantiateOffchainForm.tsx @@ -4,9 +4,9 @@ import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; import { useForm } from "react-hook-form"; -import type { OffchainDetail } from "../../../components/offchain/OffChainForm"; -import { OffChainForm } from "../../../components/offchain/OffChainForm"; import type { Option } from "lib/components/forms"; +import { OffChainForm } from "lib/components/OffChainForm"; +import type { OffchainDetail } from "lib/components/OffChainForm"; import { useContractStore } from "lib/hooks"; import { useUserKey } from "lib/hooks/useUserKey"; import type { ContractAddr } from "lib/types"; From 31cb4477c3966401e4793a908ba2e558e0cc7401 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 28 Dec 2022 15:01:43 +0700 Subject: [PATCH 23/27] fix: tag selection --- src/lib/components/OffChainForm.tsx | 5 - src/lib/components/forms/TagSelection.tsx | 431 +++++++++--------- src/lib/components/modal/EditTags.tsx | 4 - .../modal/select-contract/ListDetail.tsx | 5 - 4 files changed, 228 insertions(+), 217 deletions(-) diff --git a/src/lib/components/OffChainForm.tsx b/src/lib/components/OffChainForm.tsx index 4b23ae458..2596716c0 100644 --- a/src/lib/components/OffChainForm.tsx +++ b/src/lib/components/OffChainForm.tsx @@ -13,7 +13,6 @@ import { MAX_CONTRACT_DESCRIPTION_LENGTH, MAX_CONTRACT_NAME_LENGTH, } from "lib/data"; -import { useContractStore, useUserKey } from "lib/hooks"; import type { Option } from "lib/types"; export interface OffchainDetail { @@ -44,9 +43,6 @@ export const OffChainForm = ({ errors, labelBgColor = "background.main", }: OffChainFormProps) => { - const userKey = useUserKey(); - const { getAllTags } = useContractStore(); - return ( ({ labelBgColor={labelBgColor} /> void; @@ -50,224 +51,248 @@ const tagItemProps: CSSProperties = { marginRight: "8px", }; -export const TagSelection = forwardRef( - ( - { - options, - result, - setResult, - placeholder, - badgeBgColor = "info.dark", - helperText, - labelBgColor = "background.main", - label = "Tags", - boxWidth = "full", - creatable = true, - ...rest - }: TagSelectionProps, - ref - // TODO: refactor to reduce complexity - // eslint-disable-next-line sonarjs/cognitive-complexity - ) => { - const [optionsCopy, setOptionsCopy] = useState(options); - const [partialResult, setPartialResult] = useState([]); - const [displayOptions, setDisplayOptions] = useState(false); - const [inputValue, setInputValue] = useState(""); - const inputRef = useRef(null); - const boxRef = useRef(null); +export const TagSelection = observer( + forwardRef( + ( + { + result, + setResult, + placeholder, + badgeBgColor = "info.dark", + helperText, + labelBgColor = "background.main", + label = "Tags", + boxWidth = "full", + creatable = true, + ...rest + }: TagSelectionProps, + ref + // TODO: refactor to reduce complexity + // eslint-disable-next-line sonarjs/cognitive-complexity + ) => { + const userKey = useUserKey(); + const { getAllTags } = useContractStore(); + const options = getAllTags(userKey); - const filterOptions = (value: string) => { - setDisplayOptions(true); - setPartialResult(value ? matchSorter(optionsCopy, value) : optionsCopy); - setInputValue(value); - }; + const [optionsCopy, setOptionsCopy] = useState(options); + const [partialResult, setPartialResult] = useState([]); + const [displayOptions, setDisplayOptions] = useState(false); + const [inputValue, setInputValue] = useState(""); + const inputRef = useRef(null); + const boxRef = useRef(null); - const isOptionSelected = (option: string) => - result.some((selectedOption) => selectedOption === option); + useEffect(() => { + if (!creatable) setOptionsCopy(options); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [creatable, JSON.stringify(options)]); - const selectOption = (option: string) => { - if (isOptionSelected(option)) { - setResult(result.filter((existingOption) => existingOption !== option)); - } else { - setResult([option, ...result]); - } - }; + const filterOptions = (value: string) => { + setDisplayOptions(true); + setPartialResult(value ? matchSorter(optionsCopy, value) : optionsCopy); + setInputValue(value); + }; - const createOption = () => { - if (inputValue) { - setOptionsCopy((prev) => [...prev, inputValue]); - selectOption(inputValue); + const isOptionSelected = (option: string) => + result.some((selectedOption) => selectedOption === option); + + const selectOption = (option: string) => { + if (isOptionSelected(option)) { + setResult( + result.filter((existingOption) => existingOption !== option) + ); + } else { + setResult([option, ...result]); + } + }; + + const createOption = () => { + if (inputValue) { + setOptionsCopy((prev) => [...prev, inputValue]); + selectOption(inputValue); + setDisplayOptions(false); + if (inputRef && inputRef.current !== null) { + inputRef.current.value = ""; + } + } + }; + + const selectOptionFromList = (option: string) => { + selectOption(option); setDisplayOptions(false); if (inputRef && inputRef.current !== null) { inputRef.current.value = ""; } - } - }; - - const selectOptionFromList = (option: string) => { - selectOption(option); - setDisplayOptions(false); - if (inputRef && inputRef.current !== null) { - inputRef.current.value = ""; - } - }; - - const canCreateOption = - !optionsCopy.find((each) => each === inputValue?.toLowerCase()) && - creatable; - - const noResultAndUncreatable = !partialResult.length && !creatable; + }; - const handleKeydown = (event: KeyboardEvent) => { - if (event.key === "Enter" && canCreateOption) { - createOption(); - } - }; + const canCreateOption = + !optionsCopy.find((each) => each === inputValue?.toLowerCase()) && + creatable; - useOutsideClick({ - ref: boxRef, - handler: () => setDisplayOptions(false), - }); + const noResultAndUncreatable = !partialResult.length && !creatable; - return ( - - - - {result.length > 0 && ( - - {[...result].reverse().map((option) => ( - selectOption(option)} - key={option} - > - - {option} - - - - ))} - - )} + const handleKeydown = (event: KeyboardEvent) => { + if (event.key === "Enter" && canCreateOption) { + createOption(); + } + }; - filterOptions(e.currentTarget.value)} - onKeyDown={handleKeydown} - onFocus={() => { - setPartialResult(optionsCopy); - setDisplayOptions(true); - }} - ref={mergeRefs([inputRef, ref])} - maxLength={36} - style={{ border: "0" }} - {...rest} - /> - - {label} - - - - {helperText} - + useOutsideClick({ + ref: boxRef, + handler: () => setDisplayOptions(false), + }); - {displayOptions && ( - + + - {/* header */} - 0 && ( + + {[...result].reverse().map((option) => ( + selectOption(option)} + key={option} + > + + {option} + + + + ))} + + )} + + filterOptions(e.currentTarget.value)} + onKeyDown={handleKeydown} + onFocus={() => { + setPartialResult(optionsCopy); + setDisplayOptions(true); + }} + ref={mergeRefs([inputRef, ref])} + maxLength={36} + style={{ border: "0" }} + {...rest} + /> + - {noResultAndUncreatable ? ( - - No tags found - - ) : ( - - Select tag {creatable && "or create a new one"} - - )} - - {/* option selection section */} - {partialResult.map((option) => ( - selectOptionFromList(option)} - > - - - {option} - - {isOptionSelected(option) && ( - - )} - - - ))} - {/* creation section */} - {canCreateOption && inputValue && ( + {label} + + + + {helperText} + + + {displayOptions && ( + + {/* header */} createOption()} + p={2} + borderBottomColor="divider.main" + borderBottomWidth={noResultAndUncreatable ? "0" : "1px"} > - - Create - - {inputValue} - - + {noResultAndUncreatable ? ( + + No tags found + + ) : ( + + Select tag {creatable && "or create a new one"} + + )} - )} - - )} - - - ); - } + {/* option selection section */} + {partialResult.map((option) => ( + selectOptionFromList(option)} + > + + + {option} + + {isOptionSelected(option) && ( + + )} + + + ))} + {/* creation section */} + {canCreateOption && inputValue && ( + createOption()} + > + + Create + + {inputValue} + + + + )} + + )} + + + ); + } + ) ); diff --git a/src/lib/components/modal/EditTags.tsx b/src/lib/components/modal/EditTags.tsx index ed8e6b054..a8aa0b27b 100644 --- a/src/lib/components/modal/EditTags.tsx +++ b/src/lib/components/modal/EditTags.tsx @@ -5,7 +5,6 @@ import { MdMode } from "react-icons/md"; import { ExplorerLink } from "../ExplorerLink"; import { TagSelection } from "lib/components/forms/TagSelection"; import { ActionModal } from "lib/components/modal/ActionModal"; -import { useContractStore, useUserKey } from "lib/hooks"; import { useHandleContractSave } from "lib/hooks/useHandleSave"; import type { ContractInfo } from "lib/stores/contract"; @@ -14,8 +13,6 @@ interface EditTagsProps { } export function EditTags({ contractInfo }: EditTagsProps) { - const userKey = useUserKey(); - const { getAllTags } = useContractStore(); const [tagResult, setTagResult] = useState(contractInfo.tags ?? []); const handleSave = useHandleContractSave({ title: "Updated tags successfully!", @@ -61,7 +58,6 @@ export function EditTags({ contractInfo }: EditTagsProps) { { - const userKey = useUserKey(); - const { getAllTags } = useContractStore(); - const [tagFilter, setTagFilter] = useState([]); return ( @@ -92,7 +88,6 @@ export const ListDetail = ({ /> {!isReadOnly && ( Date: Wed, 28 Dec 2022 15:16:57 +0700 Subject: [PATCH 24/27] refactor: edit contract detail modal --- CHANGELOG.md | 2 +- ...ntract.tsx => ContractDetailsTemplate.tsx} | 23 +++++++++------ .../modal/contract/EditContractDetails.tsx | 21 ++++++++++++++ .../modal/contract/SaveContractDetails.tsx | 20 +++++++++++++ src/lib/components/modal/contract/index.ts | 3 +- .../components/ContractListTable.tsx | 28 +++++++++++-------- 6 files changed, 74 insertions(+), 23 deletions(-) rename src/lib/components/modal/contract/{EditContract.tsx => ContractDetailsTemplate.tsx} (85%) create mode 100644 src/lib/components/modal/contract/EditContractDetails.tsx create mode 100644 src/lib/components/modal/contract/SaveContractDetails.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index db1298e74..3cde4653d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements -- [#50](https://github.com/alleslabs/celatone-frontend/pull/50) Refactor offchain component to use react-form and remove redundant offchain components +- [#50](https://github.com/alleslabs/celatone-frontend/pull/50) Refactor offchain component to use react-form and remove redundant offchain components, and refactor edit contract details modal ### Bug fixes diff --git a/src/lib/components/modal/contract/EditContract.tsx b/src/lib/components/modal/contract/ContractDetailsTemplate.tsx similarity index 85% rename from src/lib/components/modal/contract/EditContract.tsx rename to src/lib/components/modal/contract/ContractDetailsTemplate.tsx index 048af9b7a..c1a30d8c2 100644 --- a/src/lib/components/modal/contract/EditContract.tsx +++ b/src/lib/components/modal/contract/ContractDetailsTemplate.tsx @@ -1,5 +1,4 @@ -import type { MenuItemProps } from "@chakra-ui/react"; -import { MenuItem, Flex, Text } from "@chakra-ui/react"; +import { Flex, Text } from "@chakra-ui/react"; import { useForm } from "react-hook-form"; import { ExplorerLink } from "lib/components/ExplorerLink"; @@ -10,11 +9,18 @@ import { useHandleContractSave } from "lib/hooks/useHandleSave"; import type { ContractInfo } from "lib/stores/contract"; import type { Option } from "lib/types"; -interface ModalProps { +interface ContractDetailsTemplateProps { + title: string; + subtitle?: string; contractInfo: ContractInfo; - menuItemProps: MenuItemProps; + triggerElement: JSX.Element; } -export const EditContract = ({ contractInfo, menuItemProps }: ModalProps) => { +export const ContractDetailsTemplate = ({ + title, + subtitle, + contractInfo, + triggerElement, +}: ContractDetailsTemplateProps) => { const defaultValues: OffchainDetail = { name: contractInfo.name ?? "", description: contractInfo.description ?? "", @@ -62,9 +68,8 @@ export const EditContract = ({ contractInfo, menuItemProps }: ModalProps) => { return ( @@ -76,7 +81,7 @@ export const EditContract = ({ contractInfo, menuItemProps }: ModalProps) => { /> } - trigger={} + trigger={triggerElement} mainBtnTitle="Save" mainAction={handleSave} disabledMain={!!errors.name || !!errors.description} diff --git a/src/lib/components/modal/contract/EditContractDetails.tsx b/src/lib/components/modal/contract/EditContractDetails.tsx new file mode 100644 index 000000000..1155b7898 --- /dev/null +++ b/src/lib/components/modal/contract/EditContractDetails.tsx @@ -0,0 +1,21 @@ +import type { ContractInfo } from "lib/stores/contract"; + +import { ContractDetailsTemplate } from "./ContractDetailsTemplate"; + +interface EditContractDetailsProps { + contractInfo: ContractInfo; + triggerElement: JSX.Element; +} +export const EditContractDetails = ({ + contractInfo, + triggerElement, +}: EditContractDetailsProps) => { + return ( + + ); +}; diff --git a/src/lib/components/modal/contract/SaveContractDetails.tsx b/src/lib/components/modal/contract/SaveContractDetails.tsx new file mode 100644 index 000000000..dba9ff642 --- /dev/null +++ b/src/lib/components/modal/contract/SaveContractDetails.tsx @@ -0,0 +1,20 @@ +import type { ContractInfo } from "lib/stores/contract"; + +import { ContractDetailsTemplate } from "./ContractDetailsTemplate"; + +interface SaveContractDetailsProps { + contractInfo: ContractInfo; + triggerElement: JSX.Element; +} +export const SaveContractDetails = ({ + contractInfo, + triggerElement, +}: SaveContractDetailsProps) => { + return ( + + ); +}; diff --git a/src/lib/components/modal/contract/index.ts b/src/lib/components/modal/contract/index.ts index c4ce90d73..8b89ff325 100644 --- a/src/lib/components/modal/contract/index.ts +++ b/src/lib/components/modal/contract/index.ts @@ -1,4 +1,5 @@ export * from "./AddToOtherList"; -export * from "./EditContract"; +export * from "./EditContractDetails"; export * from "./RemoveContract"; +export * from "./SaveContractDetails"; export * from "./SaveNewContract"; diff --git a/src/lib/pages/contracts/components/ContractListTable.tsx b/src/lib/pages/contracts/components/ContractListTable.tsx index 406d9bfe3..c25659fd3 100644 --- a/src/lib/pages/contracts/components/ContractListTable.tsx +++ b/src/lib/pages/contracts/components/ContractListTable.tsx @@ -13,6 +13,7 @@ import { MenuList, MenuButton, MenuDivider, + MenuItem, } from "@chakra-ui/react"; import Link from "next/link"; import { @@ -25,7 +26,7 @@ import { import { ExplorerLink } from "lib/components/ExplorerLink"; import { AddToOtherList, - EditContract, + EditContractDetails, RemoveContract, } from "lib/components/modal/contract"; import type { ContractInfo } from "lib/stores/contract"; @@ -129,18 +130,21 @@ export const ContractListTable = ({ /> - - ), - children: "Edit details", - }} + triggerElement={ + + } + > + Edit details + + } /> Date: Wed, 28 Dec 2022 16:05:34 +0700 Subject: [PATCH 25/27] fix: return component --- .../modal/contract/EditContractDetails.tsx | 18 ++++++++---------- .../modal/contract/SaveContractDetails.tsx | 16 +++++++--------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/lib/components/modal/contract/EditContractDetails.tsx b/src/lib/components/modal/contract/EditContractDetails.tsx index 1155b7898..f96fea363 100644 --- a/src/lib/components/modal/contract/EditContractDetails.tsx +++ b/src/lib/components/modal/contract/EditContractDetails.tsx @@ -9,13 +9,11 @@ interface EditContractDetailsProps { export const EditContractDetails = ({ contractInfo, triggerElement, -}: EditContractDetailsProps) => { - return ( - - ); -}; +}: EditContractDetailsProps) => ( + +); diff --git a/src/lib/components/modal/contract/SaveContractDetails.tsx b/src/lib/components/modal/contract/SaveContractDetails.tsx index dba9ff642..3227ecade 100644 --- a/src/lib/components/modal/contract/SaveContractDetails.tsx +++ b/src/lib/components/modal/contract/SaveContractDetails.tsx @@ -9,12 +9,10 @@ interface SaveContractDetailsProps { export const SaveContractDetails = ({ contractInfo, triggerElement, -}: SaveContractDetailsProps) => { - return ( - - ); -}; +}: SaveContractDetailsProps) => ( + +); From 1a8d774869fbc32374df18255f993e6dba6873b3 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 28 Dec 2022 19:36:10 +0700 Subject: [PATCH 26/27] fix: as commented --- src/lib/components/OffChainForm.tsx | 1 + src/lib/components/forms/ControllerInput.tsx | 1 + .../components/forms/ControllerTextarea.tsx | 14 +++++++-- .../contract/ContractDetailsTemplate.tsx | 18 +++++------- .../modal/contract/SaveNewContract.tsx | 29 +++++++++---------- .../component/InstantiateOffchainForm.tsx | 2 +- 6 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/lib/components/OffChainForm.tsx b/src/lib/components/OffChainForm.tsx index 2596716c0..5b5b50e52 100644 --- a/src/lib/components/OffChainForm.tsx +++ b/src/lib/components/OffChainForm.tsx @@ -23,6 +23,7 @@ export interface OffchainDetail { } interface OffChainFormProps { + // TODO: find a way to remove nameField and descriptionField nameField: FieldPath; descriptionField: FieldPath; state: OffchainDetail; diff --git a/src/lib/components/forms/ControllerInput.tsx b/src/lib/components/forms/ControllerInput.tsx index f0fe149b9..460e1ea26 100644 --- a/src/lib/components/forms/ControllerInput.tsx +++ b/src/lib/components/forms/ControllerInput.tsx @@ -75,6 +75,7 @@ export const ControllerInput = ({ value={watcher} onChange={field.onChange} /> + {/* TODO: add status */} {isError ? ( {error} ) : ( diff --git a/src/lib/components/forms/ControllerTextarea.tsx b/src/lib/components/forms/ControllerTextarea.tsx index 0fe85b534..941176403 100644 --- a/src/lib/components/forms/ControllerTextarea.tsx +++ b/src/lib/components/forms/ControllerTextarea.tsx @@ -12,7 +12,7 @@ import type { FieldValues, UseControllerProps, } from "react-hook-form"; -import { useController } from "react-hook-form"; +import { useWatch, useController } from "react-hook-form"; import type { TextAreaProps } from "./TextAreaInput"; @@ -34,6 +34,11 @@ export const ControllerTextarea = ({ rules = {}, ...componentProps }: ControllerTextareaProps) => { + const watcher = useWatch({ + name, + control, + }); + const { field } = useController({ name, control, rules }); const isError = !!error; @@ -54,7 +59,12 @@ export const ControllerTextarea = ({ {label} )} -