Skip to content

Commit

Permalink
feat: allow user to enter query input fields (#1227)
Browse files Browse the repository at this point in the history
* feat: allow user to enter message inputs

* chore: ui changes

* refactor

* chore: review changes
  • Loading branch information
Hemanthghs authored May 6, 2024
1 parent 7ac76d6 commit 730542f
Show file tree
Hide file tree
Showing 8 changed files with 502 additions and 81 deletions.
5 changes: 5 additions & 0 deletions frontend/public/expand-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const DialogSearchContract = (props: DialogSearchContractI) => {
const dispatch = useAppDispatch();
const handleClose = () => {
onClose();
setSearchTerm('');
setSearchResult(null);
};
const [isEnterManually, setIsEnterManually] = useState(true);
const [searchResult, setSearchResult] = useState<ContractInfoResponse | null>(
Expand All @@ -34,7 +36,8 @@ const DialogSearchContract = (props: DialogSearchContractI) => {
const [searchTerm, setSearchTerm] = useState('');
const { getContractInfo, contractLoading, contractError } = useContracts();

const onSearchContract = async () => {
const onSearchContract = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const { data } = await getContractInfo({
address: searchTerm,
baseURLs: restURLs,
Expand All @@ -56,6 +59,8 @@ const DialogSearchContract = (props: DialogSearchContractI) => {
searchResult?.contract_info?.label
);
onClose();
setSearchTerm('');
setSearchResult(null);
}
};

Expand Down Expand Up @@ -102,18 +107,18 @@ const DialogSearchContract = (props: DialogSearchContractI) => {
</div>
{isEnterManually ? (
<>
<div className="w-full flex justify-between gap-4">
<form
onSubmit={(e) => onSearchContract(e)}
className="w-full flex justify-between gap-4"
>
<SearchInputField
searchTerm={searchTerm}
setSearchTerm={(value: string) => setSearchTerm(value)}
/>
<button
onClick={() => onSearchContract()}
className="primary-gradient search-btn"
>
<button type="submit" className="primary-gradient search-btn">
Search
</button>
</div>
</form>
<div className="w-full space-y-6 h-10">
{contractLoading ? (
<div className="flex-center-center gap-2">
Expand All @@ -127,7 +132,7 @@ const DialogSearchContract = (props: DialogSearchContractI) => {
<>
{searchResult ? (
<div className="space-y-2">
<div className="font-semibold">Contract found:</div>
<div className="font-semibold">Search Result:</div>
<ContractItem
key={searchResult?.address}
name={searchResult?.contract_info?.label}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { TxStatus } from '@/types/enums';
import { CircularProgress } from '@mui/material';
import Image from 'next/image';
import React from 'react';

const MessageInputFields = ({
fields,
handleChange,
onQuery,
expandField,
queryLoading,
}: {
fields: MessageInputField[];
handleChange: (e: React.ChangeEvent<HTMLInputElement>, index: number) => void;
onQuery: (index: number) => void;
expandField: (index: number) => void;
queryLoading: TxStatus;
}) => {
return (
<div className="w-full flex flex-col gap-4">
{fields.map((field, index) => (
<div
key={field.name}
className="bg-[#ffffff14] rounded-2xl p-6 space-y-6"
>
<div className="flex justify-between items-center">
<div className="text-[14px]">{field.name}</div>
<Image
onClick={() => expandField(index)}
className="cursor-pointer"
src={'/expand-icon.svg'}
height={24}
width={24}
alt="Expand"
/>
</div>
{field?.open ? (
<div className="space-y-6">
<div className="message-input-wrapper">
<input
className="message-input-field"
type="text"
placeholder={`Enter ${field.name}`}
value={field.value}
onChange={(e) => handleChange(e, index)}
autoFocus={true}
/>
</div>
<button
type="button"
onClick={() => onQuery(index)}
className="primary-gradient text-[12px] font-medium py-[6px] px-6 leading-[20px] rounded-lg h-10 w-20 flex-center-center"
>
{queryLoading === TxStatus.PENDING ? (
<CircularProgress size={18} sx={{ color: 'white' }} />
) : (
'Query'
)}
</button>
</div>
) : null}
</div>
))}
</div>
);
};

export default MessageInputFields;
120 changes: 56 additions & 64 deletions frontend/src/app/(routes)/cosmwasm/components/QueryContract.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { useAppDispatch, useAppSelector } from '@/custom-hooks/StateHooks';
import useContracts from '@/custom-hooks/useContracts';
import { queryContractInfo } from '@/store/features/cosmwasm/cosmwasmSlice';
import { TxStatus } from '@/types/enums';
import { CircularProgress, TextField } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { queryInputStyles } from '../styles';
import { setError } from '@/store/features/common/commonSlice';
import QueryContractInputs from './QueryContractInputs';

interface QueryContractI {
address: string;
Expand All @@ -20,13 +18,25 @@ const QueryContract = (props: QueryContractI) => {
// ---------------DEPENDENCIES---------------//
// ------------------------------------------//
const dispatch = useAppDispatch();
const { getContractMessages, getQueryContract } = useContracts();
const {
getContractMessages,
getQueryContract,
getContractMessageInputs,
messagesLoading,
messageInputsLoading,
messageInputsError,
messagesError,
} = useContracts();

// ------------------------------------------//
// ------------------STATES------------------//
// ------------------------------------------//
const [queryText, setQueryText] = useState('');
const [contractMessages, setContractMessages] = useState<string[]>([]);
const [contractMessageInputs, setContractMessageInputs] = useState<string[]>(
[]
);
const [selectedMessage, setSelectedMessage] = useState('');

const queryOutput = useAppSelector(
(state) => state.cosmwasm.chains?.[chainID]?.query.queryOutput
Expand All @@ -44,8 +54,29 @@ const QueryContract = (props: QueryContractI) => {
setQueryText(e.target.value);
};

const handleSelectMessage = (msg: string) => {
const handleSelectMessage = async (msg: string) => {
setQueryText(`{\n\t"${msg}": {}\n}`);
setSelectedMessage(msg);
const { messages } = await getContractMessageInputs({
address,
baseURLs,
queryMsg: { [msg]: {} },
});
setContractMessageInputs(messages);
};

const handleSelectedMessageInputChange = (value: string) => {
setQueryText(
JSON.stringify(
{
[selectedMessage]: {
[value]: '',
},
},
undefined,
2
)
);
};

const formatJSON = () => {
Expand All @@ -69,8 +100,8 @@ const QueryContract = (props: QueryContractI) => {
// --------------------------------------//
// -----------------QUERY----------------//
// --------------------------------------//
const onQuery = () => {
if (!queryText?.length) {
const onQuery = (queryInput: string) => {
if (!queryInput?.length) {
dispatch(
setError({
type: 'error',
Expand All @@ -87,7 +118,7 @@ const QueryContract = (props: QueryContractI) => {
queryContractInfo({
address,
baseURLs,
queryData: queryText,
queryData: queryInput,
chainID,
getQueryContract,
})
Expand All @@ -106,62 +137,23 @@ const QueryContract = (props: QueryContractI) => {
}, [address]);

return (
<div className="flex gap-10">
<div className="query-input-wrapper">
<div className="space-y-4">
<div className="font-medium">Suggested Messages:</div>
<div className="flex gap-4 flex-wrap">
{contractMessages?.map((msg) => (
<div
onClick={() => handleSelectMessage(msg)}
key={msg}
className="query-shortcut-msg"
>
{msg}
</div>
))}
</div>
</div>
<div className="query-input">
<TextField
value={queryText}
name="queryField"
placeholder={JSON.stringify({ test_query: {} }, undefined, 2)}
onChange={handleQueryChange}
fullWidth
multiline
rows={7}
InputProps={{
sx: {
input: {
color: 'white',
fontSize: '14px',
padding: 2,
},
},
}}
sx={queryInputStyles}
/>
<button
onClick={onQuery}
disabled={queryLoading === TxStatus.PENDING}
className="primary-gradient query-btn"
>
{queryLoading === TxStatus.PENDING ? (
<CircularProgress size={18} sx={{ color: 'white' }} />
) : (
'Query'
)}
</button>
<button
type="button"
onClick={formatJSON}
className="format-json-btn"
>
Format JSON
</button>
</div>
</div>
<div className="grid grid-cols-2 gap-10">
<QueryContractInputs
contractMessageInputs={contractMessageInputs}
contractMessages={contractMessages}
formatJSON={formatJSON}
handleQueryChange={handleQueryChange}
handleSelectMessage={handleSelectMessage}
handleSelectedMessageInputChange={handleSelectedMessageInputChange}
messagesLoading={messagesLoading}
onQuery={onQuery}
queryLoading={queryLoading}
queryText={queryText}
selectedMessage={selectedMessage}
messageInputsLoading={messageInputsLoading}
messageInputsError={messageInputsError}
messagesError={messagesError}
/>
<div className="query-output-box overflow-y-scroll">
<div className="qeury-output">
<pre>{JSON.stringify(queryOutput, undefined, 2)}</pre>
Expand Down
Loading

0 comments on commit 730542f

Please sign in to comment.