Suggest fee button in transaction ui

This commit is contained in:
muzam1l
2022-05-30 23:01:46 +05:30
parent da9986eb66
commit ae038f17ff
4 changed files with 122 additions and 73 deletions

View File

@@ -1,5 +1,5 @@
import { Play } from "phosphor-react";
import { FC, useCallback, useEffect, useMemo, useState } from "react";
import { FC, useCallback, useEffect, useMemo } from "react";
import { useSnapshot } from "valtio";
import state from "../../state";
import {
@@ -14,7 +14,7 @@ import Button from "../Button";
import Flex from "../Flex";
import { TxJson } from "./json";
import { TxUI } from "./ui";
import estimateFee from "../../utils/estimateFee";
import { default as _estimateFee } from "../../utils/estimateFee";
export interface TransactionProps {
header: string;
@@ -145,23 +145,23 @@ const Transaction: FC<TransactionProps> = ({
[editorSavedValue, editorSettings.tabSize, prepareOptions]
);
const [estimatedFee, setEstimatedFee] = useState<string>();
useEffect(() => {
const ptx = prepareOptions(txState);
const account = accounts.find(
acc => acc.address === selectedAccount?.value
);
if (!account) return;
const estimateFee = useCallback(
async (st?: TransactionState) => {
const state = st || txState;
const ptx = prepareOptions(state);
const account = accounts.find(
acc => acc.address === state.selectedAccount?.value
);
if (!account) return;
ptx.Account = account.address;
ptx.Sequence = account.sequence;
ptx.Account = account.address;
ptx.Sequence = account.sequence;
estimateFee(ptx, account, { silent: true })
.then(res => res?.base_fee)
.then(fee => {
setEstimatedFee(fee)
});
}, [accounts, prepareOptions, selectedAccount?.value, txState]);
const res = await _estimateFee(ptx, account, { silent: true });
return res?.base_fee;
},
[accounts, prepareOptions, txState]
);
return (
<Box css={{ position: "relative", height: "calc(100% - 28px)" }} {...props}>
@@ -171,10 +171,10 @@ const Transaction: FC<TransactionProps> = ({
header={header}
state={txState}
setState={setState}
estimatedFee={estimatedFee}
estimateFee={estimateFee}
/>
) : (
<TxUI state={txState} setState={setState} estimatedFee={estimatedFee} />
<TxUI state={txState} setState={setState} estimateFee={estimateFee} />
)}
<Flex
row

View File

@@ -29,7 +29,7 @@ interface JsonProps {
header?: string;
setState: (pTx?: Partial<TransactionState> | undefined) => void;
state: TransactionState;
estimatedFee?: string
estimateFee?: () => Promise<string | undefined>;
}
export const TxJson: FC<JsonProps> = ({
@@ -37,7 +37,7 @@ export const TxJson: FC<JsonProps> = ({
state: txState,
header,
setState,
estimatedFee
estimateFee,
}) => {
const { editorSettings, accounts } = useSnapshot(state);
const { editorValue = value, selectedTransaction } = txState;
@@ -84,7 +84,7 @@ export const TxJson: FC<JsonProps> = ({
const path = `file:///${header}`;
const monaco = useMonaco();
const getSchemas = useCallback((): any[] => {
const getSchemas = useCallback(async (): Promise<any[]> => {
const tt = selectedTransaction?.value;
const txObj = transactionsData.find(td => td.TransactionType === tt);
@@ -100,6 +100,7 @@ export const TxJson: FC<JsonProps> = ({
{}
);
}
const estimatedFee = await estimateFee?.();
return [
{
uri: "file:///main-schema.json", // id of the first schema
@@ -158,13 +159,16 @@ export const TxJson: FC<JsonProps> = ({
...amountSchema,
},
];
}, [accounts, estimatedFee, header, selectedTransaction?.value]);
}, [accounts, header, selectedTransaction?.value]);
useEffect(() => {
if (!monaco) return;
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
schemas: getSchemas(),
getSchemas().then(schemas => {
console.log('seeung schmea')
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
schemas,
});
});
}, [getSchemas, monaco]);
@@ -197,12 +201,6 @@ export const TxJson: FC<JsonProps> = ({
// register onExit cb
const model = editor.getModel();
model?.onWillDispose(() => onExit(model.getValue()));
// set json defaults
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
schemas: getSchemas(),
});
}}
theme={theme === "dark" ? "dark" : "light"}
/>

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import { FC, useCallback, useState } from "react";
import Container from "../Container";
import Flex from "../Flex";
import Input from "../Input";
@@ -9,22 +9,25 @@ import {
TransactionState,
transactionsData,
TxFields,
getTxFields,
} from "../../state/transactions";
import { useSnapshot } from "valtio";
import state from "../../state";
import { streamState } from "../DebugStream";
import { Label } from "..";
import { Button } from "..";
interface UIProps {
setState: (pTx?: Partial<TransactionState> | undefined) => void;
setState: (
pTx?: Partial<TransactionState> | undefined
) => TransactionState | undefined;
state: TransactionState;
estimatedFee?: string;
estimateFee?: (state?: TransactionState) => Promise<string | undefined>;
}
export const TxUI: FC<UIProps> = ({
state: txState,
setState,
estimatedFee,
estimateFee,
}) => {
const { accounts } = useSnapshot(state);
const {
@@ -51,32 +54,54 @@ export const TxUI: FC<UIProps> = ({
}))
.filter(acc => acc.value !== selectedAccount?.value);
const resetOptions = (tt: string) => {
const txFields: TxFields | undefined = transactionsData.find(
tx => tx.TransactionType === tt
);
const [feeLoading, setFeeLoading] = useState(false);
if (!txFields) return setState({ txFields: {} });
const _txFields = Object.keys(txFields)
.filter(key => !["TransactionType", "Account", "Sequence"].includes(key))
.reduce<TxFields>(
(tf, key) => ((tf[key as keyof TxFields] = (txFields as any)[key]), tf),
{}
);
if (!_txFields.Destination) setState({ selectedDestAccount: null });
setState({ txFields: _txFields });
};
const resetOptions = useCallback(
(tt: string) => {
const fields = getTxFields(tt);
if (!fields.Destination) setState({ selectedDestAccount: null });
return setState({ txFields: fields });
},
[setState]
);
const handleSetAccount = (acc: SelectOption) => {
setState({ selectedAccount: acc });
streamState.selectedAccount = acc;
};
const handleSetField = useCallback(
(field: keyof TxFields, value: string, opFields?: TxFields) => {
const fields = opFields || txFields;
const obj = fields[field];
setState({
txFields: {
...fields,
[field]: typeof obj === "object" ? { ...obj, $value: value } : value,
},
});
},
[setState, txFields]
);
const handleEstimateFee = useCallback(
async (state?: TransactionState) => {
setFeeLoading(true);
const fee = await estimateFee?.(state);
if (fee) handleSetField("Fee", fee, state?.txFields);
setFeeLoading(false);
},
[estimateFee, handleSetField]
);
const handleChangeTxType = (tt: SelectOption) => {
setState({ selectedTransaction: tt });
resetOptions(tt.value);
const newState = resetOptions(tt.value);
handleEstimateFee(newState);
};
const specialFields = ["TransactionType", "Account", "Destination"];
@@ -85,6 +110,8 @@ export const TxUI: FC<UIProps> = ({
k => !specialFields.includes(k)
) as [keyof TxFields];
console.log("render ui");
return (
<Container
css={{
@@ -181,10 +208,7 @@ export const TxUI: FC<UIProps> = ({
let isXrp = typeof _value === "object" && _value.$type === "xrp";
const hint =
field === "Fee" && estimatedFee
? `Suggested Fee: ${estimatedFee}`
: undefined;
const isFee = field === "Fee";
return (
<Flex column key={field} css={{ mb: "$2", pr: "1px" }}>
<Flex
@@ -193,6 +217,7 @@ export const TxUI: FC<UIProps> = ({
css={{
justifyContent: "flex-end",
alignItems: "center",
position: "relative",
}}
>
<Text muted css={{ mr: "$3" }}>
@@ -201,24 +226,30 @@ export const TxUI: FC<UIProps> = ({
<Input
value={value}
onChange={e => {
setState({
txFields: {
...txFields,
[field]:
typeof _value === "object"
? { ..._value, $value: e.target.value }
: e.target.value,
},
});
handleSetField(field, e.target.value);
}}
css={{ width: "70%", flex: "inherit" }}
/>
{isFee && (
<Button
size="xs"
variant="primary"
outline
isLoading={feeLoading}
css={{
position: "absolute",
right: "$2",
fontSize: "$xs",
cursor: "pointer",
alignContent: "center",
display: "flex",
}}
onClick={() => handleEstimateFee()}
>
Suggest
</Button>
)}
</Flex>
<Label
css={{ color: "$success", textAlign: "right", mt: "$1", mb: 0, fontSize: "$sm" }}
>
{hint}
</Label>
</Flex>
);
})}

View File

@@ -93,7 +93,7 @@ export const modifyTransaction = (
Object.keys(partialTx).forEach(k => {
// Typescript mess here, but is definetly safe!
const s = tx.state as any;
const p = partialTx as any;
const p = partialTx as any; // ? Make copy
if (!deepEqual(s[k], p[k])) s[k] = p[k];
});
@@ -222,4 +222,24 @@ export const prepareState = (value: string, txState: TransactionState) => {
return tx
}
export const getTxFields = (tt: string) => {
const txFields: TxFields | undefined = transactionsData.find(
tx => tx.TransactionType === tt
);
if (!txFields) return {}
let _txFields = Object.keys(txFields)
.filter(
key => !["TransactionType", "Account", "Sequence"].includes(key)
)
.reduce<TxFields>(
(tf, key) => (
(tf[key as keyof TxFields] = (txFields as any)[key]), tf
),
{}
);
return _txFields
}
export { transactionsData }