Implement auto save

This commit is contained in:
muzam1l
2022-04-27 23:18:00 +05:30
parent ab1f45febd
commit 1d3bd128f8
3 changed files with 153 additions and 112 deletions

View File

@@ -4,6 +4,7 @@ import { useSnapshot } from "valtio";
import state from "../../state";
import {
modifyTransaction,
prepareState,
prepareTransaction,
TransactionState,
} from "../../state/transactions";
@@ -27,39 +28,43 @@ const Transaction: FC<TransactionProps> = ({
const { accounts, editorSettings } = useSnapshot(state);
const {
selectedAccount,
selectedDestAccount,
selectedTransaction,
txFields,
txIsDisabled,
txIsLoading,
viewType,
editorSavedValue,
editorValue,
} = txState;
const setState = useCallback(
(pTx?: Partial<TransactionState>) => {
modifyTransaction(header, pTx);
return modifyTransaction(header, pTx);
},
[header]
);
const prepareOptions = useCallback(() => {
const TransactionType = selectedTransaction?.value;
const Destination = selectedDestAccount?.value;
const Account = selectedAccount?.value;
const prepareOptions = useCallback(
(state: TransactionState = txState) => {
const {
selectedTransaction,
selectedDestAccount,
selectedAccount,
txFields,
} = state;
return prepareTransaction({
...txFields,
TransactionType,
Destination,
Account,
});
}, [
selectedAccount?.value,
selectedDestAccount?.value,
selectedTransaction?.value,
txFields,
]);
const TransactionType = selectedTransaction?.value;
const Destination = selectedDestAccount?.value;
const Account = selectedAccount?.value;
return prepareTransaction({
...txFields,
TransactionType,
Destination,
Account,
});
},
[txState]
);
useEffect(() => {
const transactionType = selectedTransaction?.value;
@@ -72,6 +77,15 @@ const Transaction: FC<TransactionProps> = ({
}, [txIsLoading, selectedTransaction, selectedAccount, accounts, setState]);
const submitTest = useCallback(async () => {
let st: TransactionState | undefined;
if (viewType === "json") {
// save the editor state first
const pst = prepareState(editorValue);
if (!pst) return;
st = setState(pst);
}
const account = accounts.find(
acc => acc.address === selectedAccount?.value
);
@@ -80,7 +94,7 @@ const Transaction: FC<TransactionProps> = ({
setState({ txIsLoading: true });
try {
const options = prepareOptions();
const options = prepareOptions(st);
const logPrefix = header ? `${header.split(".")[0]}: ` : undefined;
await sendTransaction(account, options, { logPrefix });
@@ -92,12 +106,14 @@ const Transaction: FC<TransactionProps> = ({
}
setState({ txIsLoading: false });
}, [
viewType,
editorValue,
accounts,
selectedTransaction?.value,
txIsDisabled,
setState,
prepareOptions,
selectedAccount?.value,
prepareOptions,
header,
]);
@@ -115,7 +131,12 @@ const Transaction: FC<TransactionProps> = ({
return (
<Box css={{ position: "relative", height: "calc(100% - 28px)" }} {...props}>
{viewType === "json" ? (
<TxJson value={jsonValue} header={header} setState={setState} />
<TxJson
value={jsonValue}
header={header}
state={txState}
setState={setState}
/>
) : (
<TxUI state={txState} setState={setState} />
)}

View File

@@ -5,7 +5,7 @@ import { useTheme } from "next-themes";
import dark from "../../theme/editor/amy.json";
import light from "../../theme/editor/xcode_default.json";
import { useSnapshot } from "valtio";
import state, { TransactionState } from "../../state";
import state, { parseJSON, prepareState, TransactionState } from "../../state";
import Text from "../Text";
import Flex from "../Flex";
import { Link } from "..";
@@ -20,25 +20,23 @@ interface JsonProps {
value?: string;
header?: string;
setState: (pTx?: Partial<TransactionState> | undefined) => void;
state: TransactionState;
}
function parseJSON(str: string): any | undefined {
try {
const parsed = JSON.parse(str);
return typeof parsed === "object" ? parsed : undefined;
} catch (error) {
return undefined;
}
}
export const TxJson: FC<JsonProps> = ({ value = "", header, setState }) => {
export const TxJson: FC<JsonProps> = ({
value = "",
state: txState,
header,
setState,
}) => {
const { editorSettings } = useSnapshot(state);
const { editorValue = value } = txState;
const { theme } = useTheme();
const [editorValue, setEditorValue] = useState(value);
const [hasUnsaved, setHasUnsaved] = useState(false);
useEffect(() => {
setEditorValue(value);
setState({ editorValue: value });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [value]);
useEffect(() => {
@@ -47,79 +45,14 @@ export const TxJson: FC<JsonProps> = ({ value = "", header, setState }) => {
}, [editorValue, value]);
const saveState = (value: string) => {
const options = parseJSON(value);
if (!options) return alert("Cannot save dirty editor");
const { Account, TransactionType, Destination, ...rest } = options;
let tx: Partial<TransactionState> = {};
if (Account) {
const acc = state.accounts.find(acc => acc.address === Account);
if (acc) {
tx.selectedAccount = {
label: acc.name,
value: acc.address,
};
} else {
tx.selectedAccount = {
label: Account,
value: Account,
};
}
} else {
tx.selectedAccount = null;
}
if (TransactionType) {
tx.selectedTransaction = {
label: TransactionType,
value: TransactionType,
};
} else {
tx.selectedTransaction = null;
}
if (Destination) {
const dest = state.accounts.find(acc => acc.address === Destination);
if (dest) {
tx.selectedDestAccount = {
label: dest.name,
value: dest.address,
};
} else {
tx.selectedDestAccount = {
label: Destination,
value: Destination,
};
}
}
Object.keys(rest).forEach(field => {
const value = rest[field];
console.log({ field, value });
if (field === "Amount") {
rest[field] = {
type: "currency",
value: +value / 1000000, // TODO handle object currencies
};
} else if (typeof value === "object") {
rest[field] = {
type: "json",
value,
};
}
});
tx.txFields = rest;
tx.editorSavedValue = null;
setState(tx);
const tx = prepareState(value);
if (tx) setState(tx);
};
const discardChanges = () => {
let discard = confirm("Are you sure to discard these changes");
if (discard) {
setEditorValue(value);
setState({ editorValue: value });
}
};
@@ -135,7 +68,7 @@ export const TxJson: FC<JsonProps> = ({ value = "", header, setState }) => {
if (!discard) {
setState({ viewType: "json", editorSavedValue: value });
} else {
setEditorValue(value);
setState({ editorValue: value });
}
};
@@ -156,7 +89,7 @@ export const TxJson: FC<JsonProps> = ({ value = "", header, setState }) => {
monaco.editor.defineTheme("light", light as any);
}}
value={editorValue}
onChange={val => setEditorValue(val || "")}
onChange={val => setState({ editorValue: val })}
onMount={(editor, monaco) => {
editor.updateOptions({
minimap: { enabled: false },

View File

@@ -1,6 +1,7 @@
import { proxy } from 'valtio';
import { deepEqual } from '../utils/object';
import transactionsData from "../content/transactions.json";
import state from '.';
export type SelectOption = {
value: string;
@@ -15,7 +16,8 @@ export interface TransactionState {
txIsDisabled: boolean;
txFields: TxFields;
viewType: 'json' | 'ui',
editorSavedValue: null | string
editorSavedValue: null | string,
editorValue?: string
}
@@ -68,14 +70,15 @@ export const modifyTransaction = (
}
if (!tx) {
const state = {
...defaultTransaction,
...partialTx,
}
transactionsState.transactions.push({
header,
state: {
...defaultTransaction,
...partialTx,
},
state,
});
return;
return state;
}
if (opts.replaceState) {
@@ -84,7 +87,7 @@ export const modifyTransaction = (
...partialTx,
}
tx.state = repTx
return
return repTx
}
Object.keys(partialTx).forEach(k => {
@@ -93,8 +96,11 @@ export const modifyTransaction = (
const p = partialTx as any;
if (!deepEqual(s[k], p[k])) s[k] = p[k];
});
return tx.state
};
// state to tx options
export const prepareTransaction = (data: any) => {
let options = { ...data };
@@ -134,4 +140,85 @@ export const prepareTransaction = (data: any) => {
return options
}
// editor value to state
export const prepareState = (value?: string) => {
const options = parseJSON(value);
if (!options) return alert("Cannot save dirty editor");
const { Account, TransactionType, Destination, ...rest } = options;
let tx: Partial<TransactionState> = {};
if (Account) {
const acc = state.accounts.find(acc => acc.address === Account);
if (acc) {
tx.selectedAccount = {
label: acc.name,
value: acc.address,
};
} else {
tx.selectedAccount = {
label: Account,
value: Account,
};
}
} else {
tx.selectedAccount = null;
}
if (TransactionType) {
tx.selectedTransaction = {
label: TransactionType,
value: TransactionType,
};
} else {
tx.selectedTransaction = null;
}
if (Destination) {
const dest = state.accounts.find(acc => acc.address === Destination);
if (dest) {
tx.selectedDestAccount = {
label: dest.name,
value: dest.address,
};
} else {
tx.selectedDestAccount = {
label: Destination,
value: Destination,
};
}
}
Object.keys(rest).forEach(field => {
const value = rest[field];
console.log({ field, value });
if (field === "Amount") {
rest[field] = {
type: "currency",
value: +value / 1000000, // TODO handle object currencies
};
} else if (typeof value === "object") {
rest[field] = {
type: "json",
value,
};
}
});
tx.txFields = rest;
tx.editorSavedValue = null;
return tx
}
export const parseJSON = (str?: string | null): any | undefined => {
if (!str) return undefined
try {
const parsed = JSON.parse(str);
return typeof parsed === "object" ? parsed : undefined;
} catch (error) {
return undefined;
}
}
export { transactionsData }