diff --git a/components/ActivitiesTable/index.tsx b/components/ActivitiesTable/index.tsx index 832288ac..93e537b9 100644 --- a/components/ActivitiesTable/index.tsx +++ b/components/ActivitiesTable/index.tsx @@ -75,7 +75,6 @@ const ActivitiesTable: React.FC = ({ > = ({ open, onClose, ad const { accounts, password } = useWalletsContext() const isMobile = useIsMobile() + const sendTransaction = useSendTransaction() const [loading, setLoading] = React.useState(false) const [memo, setMemo] = React.useState('') const [amount, setAmount] = React.useState('') @@ -79,7 +80,7 @@ const AddressSendDialog: React.FC = ({ open, onClose, ad availableTokens.coins, availableTokens.tokens_prices ) - const msg = { + const msg: TransactionMsgSend = { typeUrl: '/cosmos.bank.v1beta1.MsgSend', value: { fromAddress: sender.address, @@ -87,7 +88,8 @@ const AddressSendDialog: React.FC = ({ open, onClose, ad amount: [{ amount: coinsToSend.amount.toString(), denom: coinsToSend.denom }], }, } - await invoke(window, 'forboleX.sendTransaction', password, sender.address, { + + await sendTransaction(password, sender.address, { msgs: [msg], memo, }) @@ -97,7 +99,7 @@ const AddressSendDialog: React.FC = ({ open, onClose, ad setLoading(false) } }, - [availableTokens] + [availableTokens, sendTransaction] ) const insufficientTokens = React.useMemo(() => { diff --git a/components/ConfirmTransactionDialog/index.tsx b/components/ConfirmTransactionDialog/index.tsx index 3e5bf794..c42171c3 100644 --- a/components/ConfirmTransactionDialog/index.tsx +++ b/components/ConfirmTransactionDialog/index.tsx @@ -11,7 +11,7 @@ import useStyles from './styles' import useIsMobile from '../../misc/useIsMobile' import { useWalletsContext } from '../../contexts/WalletsContext' import { getTokensPrices } from '../../graphql/queries/tokensPrices' -// import CloseIcon from '../../assets/images/icons/icon_cross.svg' +import CloseIcon from '../../assets/images/icons/icon_cross.svg' import BackIcon from '../../assets/images/icons/icon_back.svg' import useIconProps from '../../misc/useIconProps' import { getValidatorsByAddresses } from '../../graphql/queries/validators' @@ -24,6 +24,7 @@ import sendMsgToChromeExt from '../../misc/sendMsgToChromeExt' import cryptocurrencies from '../../misc/cryptocurrencies' import useSignerInfo from '../../misc/useSignerInfo' import signAndBroadcastTransaction from '../../misc/signAndBroadcastTransaction' +import useIsChromeExt from '../../misc/useIsChromeExt' enum ConfirmTransactionStage { ConfirmStage = 'confirm', @@ -56,6 +57,7 @@ const ConfirmTransactionDialog: React.FC = ({ const classes = useStyles() const isMobile = useIsMobile() const iconProps = useIconProps() + const { isSentFromWeb } = useIsChromeExt() const { accounts, password, wallets } = useWalletsContext() const account = accounts.find((a) => a.address === address) @@ -184,6 +186,14 @@ const ConfirmTransactionDialog: React.FC = ({ const [loading, setLoading] = React.useState(false) + const closeDialog = React.useCallback(() => { + if (isSentFromWeb) { + sendMsgToChromeExt({ event: 'closeChromeExtension' }) + } else { + onClose() + } + }, [isSentFromWeb]) + const confirm = React.useCallback( async (securityPassword?: string, ledgerSigner?: any) => { try { @@ -255,24 +265,14 @@ const ConfirmTransactionDialog: React.FC = ({ return { title: '', dialogWidth: 'sm', - content: ( - sendMsgToChromeExt({ event: 'closeChromeExtension' })} - /> - ), + content: , } case ConfirmTransactionStage.FailStage: default: return { title: '', dialogWidth: 'sm', - content: ( - sendMsgToChromeExt({ event: 'closeChromeExtension' })} - /> - ), + content: , } } }, [stage, t, transactionData, account, validators, wallet, confirm, successMessage, totalAmount]) @@ -284,9 +284,11 @@ const ConfirmTransactionDialog: React.FC = ({ ) : null} - {/* - - */} + {isSentFromWeb ? ( + + + + ) : null} {content.title ? {content.title} : null} {account && wallet && denoms ? content.content : null} diff --git a/components/CreateProposalForm/index.tsx b/components/CreateProposalForm/index.tsx index 050a952e..29147af2 100644 --- a/components/CreateProposalForm/index.tsx +++ b/components/CreateProposalForm/index.tsx @@ -13,7 +13,6 @@ import { import { Autocomplete } from '@material-ui/lab' import useTranslation from 'next-translate/useTranslation' import keyBy from 'lodash/keyBy' -import invoke from 'lodash/invoke' import last from 'lodash/last' import useIconProps from '../../misc/useIconProps' import { useGetStyles } from './styles' @@ -22,6 +21,7 @@ import { useWalletsContext } from '../../contexts/WalletsContext' import cryptocurrencies from '../../misc/cryptocurrencies' import RemoveIcon from '../../assets/images/icons/icon_clear.svg' import TokenAmountInput from '../TokenAmountInput' +import useSendTransaction from '../../misc/useSendTransaction' interface CreateProposalFormProps { account: Account @@ -34,6 +34,7 @@ const CreateProposalForm: React.FC = ({ account }) => { const { accounts, password } = useWalletsContext() const iconProps = useIconProps() + const sendTransaction = useSendTransaction() const types = [ '/cosmos.gov.v1beta1.TextProposal', @@ -82,7 +83,7 @@ const CreateProposalForm: React.FC = ({ account }) => { title, description, changes: [ - changes.map((x, y) => ({ + changes.map((x) => ({ subspace: x.subspace, key: x.key, value: x.value, @@ -110,7 +111,7 @@ const CreateProposalForm: React.FC = ({ account }) => { recipient, amount: [ { - amount: String(Number(amount) * 10 ** 6), // TODO: handle by token_units + amount: String(Number(amount) * 10 ** 6), denom: network.defaultGasFee.amount.denom, }, ], @@ -120,8 +121,9 @@ const CreateProposalForm: React.FC = ({ account }) => { initialDeposit: [], proposer: proposalAccount.address, }, - } - await invoke(window, 'forboleX.sendTransaction', password, proposalAccount.address, { + } as unknown as TransactionMsgSubmitProposal + + await sendTransaction(password, proposalAccount.address, { msgs: [msg], memo, }) diff --git a/components/DelegationDialog/index.tsx b/components/DelegationDialog/index.tsx index 811f0ddb..d22ff12e 100644 --- a/components/DelegationDialog/index.tsx +++ b/components/DelegationDialog/index.tsx @@ -2,7 +2,6 @@ import { Typography, Box, Dialog, DialogTitle, IconButton, DialogContent } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import React from 'react' -import invoke from 'lodash/invoke' import CloseIcon from '../../assets/images/icons/icon_cross.svg' import BackIcon from '../../assets/images/icons/icon_back.svg' import useStyles from './styles' @@ -17,6 +16,7 @@ import cryptocurrencies from '../../misc/cryptocurrencies' import ImageDefaultDark from '../../assets/images/image_default_dark.svg' import ImageDefaultLight from '../../assets/images/image_default_light.svg' import { useGeneralContext } from '../../contexts/GeneralContext' +import useSendTransaction from '../../misc/useSendTransaction' enum DelegationStage { SelectAmountStage = 'select amount', @@ -52,6 +52,7 @@ const DelegationDialog: React.FC = ({ const { password } = useWalletsContext() const { theme } = useGeneralContext() const isMobile = useIsMobile() + const sendTransaction = useSendTransaction() const [amount, setAmount] = React.useState(0) const [denom, setDenom] = React.useState('') const [delegations, setDelegations] = React.useState< @@ -83,27 +84,25 @@ const DelegationDialog: React.FC = ({ async (d: Array<{ amount: number; validator: Validator }>, memo: string) => { try { setLoading(true) - const msgs = d - .map((r) => { - const coinsToSend = getEquivalentCoinToSend( - { amount: r.amount, denom }, - availableTokens.coins, - availableTokens.tokens_prices - ) - return { - typeUrl: '/cosmos.staking.v1beta1.MsgDelegate', - value: { - delegatorAddress: account.address, - validatorAddress: r.validator.address, - amount: { - amount: Math.round(coinsToSend.amount).toString(), - denom: coinsToSend.denom, - }, + const msgs: TransactionMsgDelegate[] = d.map((r) => { + const coinsToSend = getEquivalentCoinToSend( + { amount: r.amount, denom }, + availableTokens.coins, + availableTokens.tokens_prices + ) + return { + typeUrl: '/cosmos.staking.v1beta1.MsgDelegate', + value: { + delegatorAddress: account.address, + validatorAddress: r.validator.address, + amount: { + amount: Math.round(coinsToSend.amount).toString(), + denom: coinsToSend.denom, }, - } - }) - .filter((a) => a) - await invoke(window, 'forboleX.sendTransaction', password, account.address, { + }, + } + }) + await sendTransaction(password, account.address, { msgs, memo, }) @@ -113,7 +112,7 @@ const DelegationDialog: React.FC = ({ setLoading(false) } }, - [setStage, password, availableTokens, account, denom] + [setStage, password, availableTokens, account, denom, sendTransaction] ) const content: Content = React.useMemo(() => { diff --git a/components/DepositDialog/index.tsx b/components/DepositDialog/index.tsx index 853fb8e4..2fe49e5f 100644 --- a/components/DepositDialog/index.tsx +++ b/components/DepositDialog/index.tsx @@ -3,7 +3,6 @@ import useTranslation from 'next-translate/useTranslation' import React from 'react' import { gql, useSubscription } from '@apollo/client' import get from 'lodash/get' -import invoke from 'lodash/invoke' import CloseIcon from '../../assets/images/icons/icon_cross.svg' import useStyles from './styles' import useIconProps from '../../misc/useIconProps' @@ -11,6 +10,7 @@ import InputAmount from './InputAmount' import { getEquivalentCoinToSend } from '../../misc/utils' import { getLatestAccountBalance } from '../../graphql/queries/accountBalances' import { useWalletsContext } from '../../contexts/WalletsContext' +import useSendTransaction from '../../misc/useSendTransaction' interface DepositDialogProps { crypto: Cryptocurrency @@ -25,6 +25,7 @@ const DepositDialog: React.FC = ({ crypto, open, onClose, pr const iconProps = useIconProps() const { password, accounts: allAccounts } = useWalletsContext() const accounts = allAccounts.filter((a) => a.crypto === crypto.name) + const sendTransaction = useSendTransaction() const [loading, setLoading] = React.useState(false) const [address, setAddress] = React.useState('') @@ -58,7 +59,7 @@ const DepositDialog: React.FC = ({ crypto, open, onClose, pr amount: [{ amount: coinsToSend.amount.toString(), denom: coinsToSend.denom }], }, } - await invoke(window, 'forboleX.sendTransaction', password, depositor, { + await sendTransaction(password, depositor, { msgs: [msg], memo, }) @@ -69,7 +70,7 @@ const DepositDialog: React.FC = ({ crypto, open, onClose, pr console.log(err) } }, - [availableTokens] + [availableTokens, sendTransaction] ) return ( diff --git a/components/EditAccountDialog/index.tsx b/components/EditAccountDialog/index.tsx index 0cb5c90b..34f382fc 100644 --- a/components/EditAccountDialog/index.tsx +++ b/components/EditAccountDialog/index.tsx @@ -2,7 +2,6 @@ import { Dialog, DialogTitle, IconButton, DialogContent, Box, Typography } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import React from 'react' -import invoke from 'lodash/invoke' import get from 'lodash/get' import { useSubscription, gql } from '@apollo/client' import CloseIcon from '../../assets/images/icons/icon_cross.svg' @@ -17,6 +16,7 @@ import useIsMobile from '../../misc/useIsMobile' import EditRewardAddress from './EditRewardAddress' import RemoveAccount from './RemoveAccount' import { getWithdrawAddress } from '../../graphql/queries/withdrawAddress' +import useSendTransaction from '../../misc/useSendTransaction' enum EditAccountStage { AccountInfoStage = 'account info', @@ -44,6 +44,7 @@ const EditAccountDialog: React.FC = ({ account, open, on const iconProps = useIconProps() const { updateAccount, password } = useWalletsContext() const isMobile = useIsMobile() + const sendTransaction = useSendTransaction() const { data } = useSubscription( gql` @@ -76,14 +77,14 @@ const EditAccountDialog: React.FC = ({ account, open, on async (newWithdrawAddress: string, memo: string) => { try { setLoading(true) - const msg = { + const msg: TransactionMsgSetWithdrawAddress = { typeUrl: '/cosmos.distribution.v1beta1.MsgSetWithdrawAddress', value: { delegatorAddress: account.address, withdrawAddress: newWithdrawAddress, }, } - await invoke(window, 'forboleX.sendTransaction', password, account.address, { + await sendTransaction(password, account.address, { msgs: [msg], memo, }) @@ -93,7 +94,7 @@ const EditAccountDialog: React.FC = ({ account, open, on setLoading(false) } }, - [setStage, account] + [setStage, account, sendTransaction] ) const content: Content = React.useMemo(() => { diff --git a/components/IBCTransferDialog/index.tsx b/components/IBCTransferDialog/index.tsx index 9441305f..bb61d7c2 100644 --- a/components/IBCTransferDialog/index.tsx +++ b/components/IBCTransferDialog/index.tsx @@ -2,7 +2,6 @@ import { Dialog, DialogTitle, IconButton } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import React from 'react' -import invoke from 'lodash/invoke' import CloseIcon from '../../assets/images/icons/icon_cross.svg' import BackIcon from '../../assets/images/icons/icon_back.svg' import useStyles from './styles' @@ -15,6 +14,7 @@ import SelectChain from './SelectChain' import AddChannel from './AddChannel' import SelectDetails from './SelectDetails' import cryptocurrencies from '../../misc/cryptocurrencies' +import useSendTransaction from '../../misc/useSendTransaction' enum IBCTransferStage { SelectChainStage = 'select chain', @@ -46,6 +46,7 @@ const IBCTransferDialog: React.FC = ({ const iconProps = useIconProps() const { password } = useWalletsContext() const isMobile = useIsMobile() + const sendTransaction = useSendTransaction() const [channel, setChannel] = React.useState('') const [chainId, setChainId] = React.useState('') @@ -79,7 +80,7 @@ const IBCTransferDialog: React.FC = ({ availableTokens.coins, availableTokens.tokens_prices ) - const msgs = [ + const msgs: TransactionMsgIBCTransfer[] = [ { typeUrl: '/ibc.applications.transfer.v1.MsgTransfer', value: { @@ -92,7 +93,7 @@ const IBCTransferDialog: React.FC = ({ }, }, ] - await invoke(window, 'forboleX.sendTransaction', password, account.address, { + await sendTransaction(password, account.address, { msgs, memo, }) @@ -102,7 +103,7 @@ const IBCTransferDialog: React.FC = ({ setLoading(false) } }, - [setStage, password, availableTokens, account, channel] + [setStage, password, availableTokens, account, channel, sendTransaction] ) const content: Content = React.useMemo(() => { diff --git a/components/Layout/index.tsx b/components/Layout/index.tsx index d1f3c536..b44af7ff 100644 --- a/components/Layout/index.tsx +++ b/components/Layout/index.tsx @@ -12,6 +12,7 @@ import UnlockPasswordDialog from '../UnlockPasswordDialog' import usePersistedState from '../../misc/usePersistedState' import ConfirmTransactionDialog from '../ConfirmTransactionDialog' import ChromeExtDialog from '../ChromeExtDialog' +import useIsChromeExt from '../../misc/useIsChromeExt' export enum MenuWidth { Expanded = 32, @@ -37,15 +38,7 @@ const Layout: React.FC = ({ const { isFirstTimeUser, isUnlocked, isChromeExtInstalled } = useWalletsContext() // Hide menu for chrome extension const router = useRouter() - const hideMenuQueryParam = get(router, 'query.hideMenu', '') - const isHideMenu = hideMenuQueryParam || (process.browser && (window as any).hideMenu) - - React.useEffect(() => { - if (hideMenuQueryParam) { - // eslint-disable-next-line @typescript-eslint/no-extra-semi - ;(window as any).hideMenu = true - } - }, [hideMenuQueryParam]) + const { isChromeExt } = useIsChromeExt() // Open ConfirmTransactionDialog with correct query params const { address, transactionData, open, onClose } = React.useMemo(() => { @@ -69,9 +62,9 @@ const Layout: React.FC = ({ - {isHideMenu ? null : ( + {isChromeExt ? null : ( = ({ e.stopPropagation(), + }, + }, + }, +} + +const Markdown = (props: any) => { + return +} + +export default Markdown diff --git a/components/ProfileDialog/index.tsx b/components/ProfileDialog/index.tsx index abf2dda7..ab4d1406 100644 --- a/components/ProfileDialog/index.tsx +++ b/components/ProfileDialog/index.tsx @@ -14,13 +14,13 @@ import { } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import React from 'react' -import invoke from 'lodash/invoke' import CloseIcon from '../../assets/images/icons/icon_cross.svg' import useStyles from './styles' import useIconProps from '../../misc/useIconProps' import CameraIcon from '../../assets/images/icons/icon_camera.svg' import { useGeneralContext } from '../../contexts/GeneralContext' import { useWalletsContext } from '../../contexts/WalletsContext' +import useSendTransaction from '../../misc/useSendTransaction' interface ProfileDialogProps { open: boolean @@ -41,6 +41,7 @@ const ProfileDialog: React.FC = ({ const themeStyle = useTheme() const { theme } = useGeneralContext() const { password } = useWalletsContext() + const sendTransaction = useSendTransaction() const [loading, setLoading] = React.useState(false) const [profile, setProfile] = React.useState(defaultProfile) @@ -55,7 +56,7 @@ const ProfileDialog: React.FC = ({ const onSubmit = React.useCallback(async () => { try { setLoading(true) - const msgs = [ + const msgs: TransactionMsgSaveProfile[] = [ { typeUrl: '/desmos.profiles.v1beta1.MsgSaveProfile', value: { @@ -68,7 +69,7 @@ const ProfileDialog: React.FC = ({ }, }, ] - await invoke(window, 'forboleX.sendTransaction', password, account.address, { + await sendTransaction(password, account.address, { msgs, memo: '', }) @@ -77,7 +78,7 @@ const ProfileDialog: React.FC = ({ } catch (err) { setLoading(false) } - }, [password, account, profile]) + }, [password, account, profile, sendTransaction]) return ( diff --git a/components/ProposalDetail/index.tsx b/components/ProposalDetail/index.tsx index dc4dba43..097a480e 100644 --- a/components/ProposalDetail/index.tsx +++ b/components/ProposalDetail/index.tsx @@ -27,6 +27,7 @@ import VoteDialog from '../VoteDialog' import VoteResult from './VoteResult' import VoteTable from './VoteTable' import { formatTokenAmount, getTokenAmountFromDenoms } from '../../misc/utils' +import Markdown from '../Markdown' export interface VoteSummary { amount: number @@ -127,7 +128,7 @@ const ProposalDetail: React.FC = ({ - + {`#${proposal.id}`} @@ -151,7 +152,7 @@ const ProposalDetail: React.FC = ({ - {proposal.description} + {proposal.description || ''} {/* Software Upgrade Proposal */} diff --git a/components/ProposalTable/index.tsx b/components/ProposalTable/index.tsx index d74378da..ce1724be 100644 --- a/components/ProposalTable/index.tsx +++ b/components/ProposalTable/index.tsx @@ -7,6 +7,7 @@ import Active from './Active' import InActive from './InActive' import VoteDialog from '../VoteDialog' import DepositDialog from '../DepositDialog' +import Markdown from '../Markdown' interface ProposalsTableProps { proposals: Proposal[] @@ -64,7 +65,7 @@ const ProposalTable: React.FC = ({ proposals, crypto }) => {x.title} - {x.description} + {x.description || ''} {x.tag === 'deposit' diff --git a/components/RedelegateDialog/index.tsx b/components/RedelegateDialog/index.tsx index 6ebb196c..251440f6 100644 --- a/components/RedelegateDialog/index.tsx +++ b/components/RedelegateDialog/index.tsx @@ -2,7 +2,6 @@ import { Dialog, DialogTitle, IconButton } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import React from 'react' -import invoke from 'lodash/invoke' import CloseIcon from '../../assets/images/icons/icon_cross.svg' import BackIcon from '../../assets/images/icons/icon_back.svg' import useStyles from './styles' @@ -14,6 +13,7 @@ import { getEquivalentCoinToSend, getTokenAmountFromDenoms } from '../../misc/ut import cryptocurrencies from '../../misc/cryptocurrencies' import { useWalletsContext } from '../../contexts/WalletsContext' import useIsMobile from '../../misc/useIsMobile' +import useSendTransaction from '../../misc/useSendTransaction' enum RedelegationStage { SelectAmountStage = 'select amount', @@ -50,6 +50,7 @@ const RedelegationDialog: React.FC = ({ const iconProps = useIconProps() const { password } = useWalletsContext() const isMobile = useIsMobile() + const sendTransaction = useSendTransaction() const crypto = account ? cryptocurrencies[account.crypto] : Object.values(cryptocurrencies)[0] const [amount, setAmount] = React.useState(0) const [denom, setDenom] = React.useState('') @@ -82,7 +83,7 @@ const RedelegationDialog: React.FC = ({ delegatedTokens, tokensPrices ) - await invoke(window, 'forboleX.sendTransaction', password, account.address, { + await sendTransaction(password, account.address, { msgs: [ { typeUrl: '/cosmos.staking.v1beta1.MsgBeginRedelegate', @@ -102,7 +103,16 @@ const RedelegationDialog: React.FC = ({ setLoading(false) } }, - [amount, denom, delegatedTokens, tokensPrices, password, account, fromValidator] + [ + amount, + denom, + delegatedTokens, + tokensPrices, + password, + account, + fromValidator, + sendTransaction, + ] ) const content: Content = React.useMemo(() => { diff --git a/components/SendDialog/index.tsx b/components/SendDialog/index.tsx index 05dce367..09a8178f 100644 --- a/components/SendDialog/index.tsx +++ b/components/SendDialog/index.tsx @@ -2,7 +2,6 @@ import { Dialog, DialogTitle, IconButton, DialogContent, Box, Typography } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import React from 'react' -import invoke from 'lodash/invoke' import CloseIcon from '../../assets/images/icons/icon_cross.svg' import useStyles from './styles' import useIconProps from '../../misc/useIconProps' @@ -14,6 +13,7 @@ import { useGeneralContext } from '../../contexts/GeneralContext' import ImageDefaultDark from '../../assets/images/image_default_dark.svg' import ImageDefaultLight from '../../assets/images/image_default_light.svg' import cryptocurrencies from '../../misc/cryptocurrencies' +import useSendTransaction from '../../misc/useSendTransaction' interface SendDialogProps { account: Account @@ -28,6 +28,7 @@ const SendDialog: React.FC = ({ account, availableTokens, open, const iconProps = useIconProps() const { password } = useWalletsContext() const isMobile = useIsMobile() + const sendTransaction = useSendTransaction() const [loading, setLoading] = React.useState(false) const { theme } = useGeneralContext() const crypto = account ? cryptocurrencies[account.crypto] : Object.values(cryptocurrencies)[0] @@ -44,24 +45,22 @@ const SendDialog: React.FC = ({ account, availableTokens, open, ) => { try { setLoading(true) - const msgs = recipients - .map((r) => { - const coinsToSend = getEquivalentCoinToSend( - r.amount, - availableTokens.coins, - availableTokens.tokens_prices - ) - return { - typeUrl: '/cosmos.bank.v1beta1.MsgSend', - value: { - fromAddress: account.address, - toAddress: r.address, - amount: [{ amount: coinsToSend.amount.toString(), denom: coinsToSend.denom }], - }, - } - }) - .filter((a) => a) - await invoke(window, 'forboleX.sendTransaction', password, account.address, { + const msgs: TransactionMsgSend[] = recipients.map((r) => { + const coinsToSend = getEquivalentCoinToSend( + r.amount, + availableTokens.coins, + availableTokens.tokens_prices + ) + return { + typeUrl: '/cosmos.bank.v1beta1.MsgSend', + value: { + fromAddress: account.address, + toAddress: r.address, + amount: [{ amount: coinsToSend.amount.toString(), denom: coinsToSend.denom }], + }, + } + }) + await sendTransaction(password, account.address, { msgs, memo, }) @@ -71,7 +70,7 @@ const SendDialog: React.FC = ({ account, availableTokens, open, setLoading(false) } }, - [availableTokens] + [availableTokens, sendTransaction] ) React.useEffect(() => { diff --git a/components/UndelegateDialog/index.tsx b/components/UndelegateDialog/index.tsx index 639f92ba..0771b00b 100644 --- a/components/UndelegateDialog/index.tsx +++ b/components/UndelegateDialog/index.tsx @@ -2,7 +2,6 @@ import { Dialog, DialogTitle, IconButton } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import React from 'react' -import invoke from 'lodash/invoke' import CloseIcon from '../../assets/images/icons/icon_cross.svg' import useStyles from './styles' import useIconProps from '../../misc/useIconProps' @@ -11,6 +10,7 @@ import { getEquivalentCoinToSend, getTokenAmountFromDenoms } from '../../misc/ut import cryptocurrencies from '../../misc/cryptocurrencies' import { useWalletsContext } from '../../contexts/WalletsContext' import useIsMobile from '../../misc/useIsMobile' +import useSendTransaction from '../../misc/useSendTransaction' interface UndelegationDialogProps { account: Account @@ -34,6 +34,7 @@ const UndelegationDialog: React.FC = ({ const iconProps = useIconProps() const { password } = useWalletsContext() const isMobile = useIsMobile() + const sendTransaction = useSendTransaction() const crypto = account ? cryptocurrencies[account.crypto] : Object.values(cryptocurrencies)[0] const [loading, setLoading] = React.useState(false) @@ -51,7 +52,7 @@ const UndelegationDialog: React.FC = ({ delegatedTokens, tokensPrices ) - await invoke(window, 'forboleX.sendTransaction', password, account.address, { + await sendTransaction(password, account.address, { msgs: [ { typeUrl: '/cosmos.staking.v1beta1.MsgUndelegate', @@ -70,7 +71,7 @@ const UndelegationDialog: React.FC = ({ setLoading(false) } }, - [delegatedTokens, tokensPrices, account, password, account] + [delegatedTokens, tokensPrices, account, password, account, sendTransaction] ) React.useEffect(() => { diff --git a/components/ValidatorAvatar/styles.ts b/components/ValidatorAvatar/styles.ts index b1998e2e..9ecb244f 100644 --- a/components/ValidatorAvatar/styles.ts +++ b/components/ValidatorAvatar/styles.ts @@ -13,7 +13,7 @@ const useStyles = makeStyles( wrapText: { maxWidth: theme.spacing(18), textOverflow: 'ellipsis', - whiteSpace: 'nowrap', + whiteSpace: 'unset', overflow: 'hidden', [theme.breakpoints.down('sm')]: { maxWidth: theme.spacing(6), diff --git a/components/VoteDialog/index.tsx b/components/VoteDialog/index.tsx index 01b8065b..bd6e9f7e 100644 --- a/components/VoteDialog/index.tsx +++ b/components/VoteDialog/index.tsx @@ -1,12 +1,12 @@ import { Dialog, DialogTitle, IconButton } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import React from 'react' -import invoke from 'lodash/invoke' import CloseIcon from '../../assets/images/icons/icon_cross.svg' import useStyles from './styles' import useIconProps from '../../misc/useIconProps' import SelectAnswer from './SelectAnswer' import { useWalletsContext } from '../../contexts/WalletsContext' +import useSendTransaction from '../../misc/useSendTransaction' interface VoteDialogProps { crypto: Cryptocurrency @@ -20,6 +20,7 @@ const VoteDialog: React.FC = ({ crypto, open, onClose, proposal const classes = useStyles() const iconProps = useIconProps() const { password } = useWalletsContext() + const sendTransaction = useSendTransaction() const [loading, setLoading] = React.useState(false) @@ -40,8 +41,8 @@ const VoteDialog: React.FC = ({ crypto, open, onClose, proposal proposalId: proposal.id, voter: account.address, }, - } - await invoke(window, 'forboleX.sendTransaction', password, account.address, { + } as unknown as TransactionMsgVote + await sendTransaction(password, account.address, { msgs: [msg], memo, }) @@ -52,7 +53,7 @@ const VoteDialog: React.FC = ({ crypto, open, onClose, proposal console.log(err) } }, - [proposal, password] + [proposal, password, sendTransaction] ) return ( diff --git a/components/WithdrawRewardsDialog/index.tsx b/components/WithdrawRewardsDialog/index.tsx index c25270de..d1922af1 100644 --- a/components/WithdrawRewardsDialog/index.tsx +++ b/components/WithdrawRewardsDialog/index.tsx @@ -2,7 +2,6 @@ import { Dialog, DialogTitle, IconButton } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import React from 'react' import cloneDeep from 'lodash/cloneDeep' -import invoke from 'lodash/invoke' import CloseIcon from '../../assets/images/icons/icon_cross.svg' import useStyles from './styles' import useIconProps from '../../misc/useIconProps' @@ -10,6 +9,7 @@ import SelectValidators from './SelectValidators' import { useWalletsContext } from '../../contexts/WalletsContext' import cryptocurrencies from '../../misc/cryptocurrencies' import useIsMobile from '../../misc/useIsMobile' +import useSendTransaction from '../../misc/useSendTransaction' export interface ValidatorTag extends Validator { isSelected: boolean @@ -39,6 +39,7 @@ const WithdrawRewardsDialog: React.FC = ({ const classes = useStyles() const iconProps = useIconProps() const isMobile = useIsMobile() + const sendTransaction = useSendTransaction() const crypto = account ? cryptocurrencies[account.crypto] : Object.values(cryptocurrencies)[0] const [loading, setLoading] = React.useState(false) const { password } = useWalletsContext() @@ -47,16 +48,14 @@ const WithdrawRewardsDialog: React.FC = ({ async (delegations: Array, memo: string) => { try { setLoading(true) - const msgs = delegations - .map((r) => ({ - typeUrl: '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', - value: { - delegatorAddress: account.address, - validatorAddress: r.address, - }, - })) - .filter((a) => a) - await invoke(window, 'forboleX.sendTransaction', password, account.address, { + const msgs: TransactionMsgWithdrawReward[] = delegations.map((r) => ({ + typeUrl: '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', + value: { + delegatorAddress: account.address, + validatorAddress: r.address, + }, + })) + await sendTransaction(password, account.address, { msgs, memo, }) @@ -66,7 +65,7 @@ const WithdrawRewardsDialog: React.FC = ({ setLoading(false) } }, - [password, account] + [password, account, sendTransaction] ) const totalAmount = React.useMemo(() => { diff --git a/locales/en/common.json b/locales/en/common.json index 55ff06cb..53ba33ef 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -303,7 +303,7 @@ "no rewards yet": "No Rewards Yet", "delegate your token and get some rewards": "Delegate your token and get some rewards", "total": "Total Amount", - "withdraw warning ledger": "Due to the limitation of Ledgr device, using Ledger Nano S, Forbole X can olny withdraw rewards from up to 5 validators at a time. Using Ledger Nano X, Forbole X can olny withdraw rewards from 20 validators at a time.", + "withdraw warning ledger": "Due to the limitation of Ledger device, using Ledger Nano S, Forbole X can olny withdraw rewards from up to 5 validators at a time. Using Ledger Nano X, Forbole X can olny withdraw rewards from 20 validators at a time.", "withdraw warning secret recovery phrase": "Forbole X can olny withdraw rewards from up to 20 validators at a time.", "you have not added any address": "You have not added any address", "edit address": "Edit Address", diff --git a/locales/zh/common.json b/locales/zh/common.json index 3966c96f..cd4e18f8 100644 --- a/locales/zh/common.json +++ b/locales/zh/common.json @@ -299,7 +299,7 @@ "no rewards yet": "[zh] No Rewards Yet", "delegate your token and get some rewards": "[zh] Delegate your token and get some rewards", "total": "[zh] Total Amount", - "withdraw warning ledger": "[zh] Due to the limitation of Ledgr device, using Ledger Nano S, Forbole X can olny withdraw rewards from 5 validators at a time. Using Ledger Nano X, Forbole X can olny withdraw rewards from 20 validators at a time.", + "withdraw warning ledger": "[zh] Due to the limitation of Ledger device, using Ledger Nano S, Forbole X can olny withdraw rewards from 5 validators at a time. Using Ledger Nano X, Forbole X can olny withdraw rewards from 20 validators at a time.", "withdraw warning secret recovery": "[zh] Forbole X can olny withdraw rewards from 20 validators at a time.", "you have not added any address": "[zh] You have not added any address", "edit address": "[zh] Edit Address", diff --git a/misc/useIsChromeExt.ts b/misc/useIsChromeExt.ts new file mode 100644 index 00000000..1b9101b9 --- /dev/null +++ b/misc/useIsChromeExt.ts @@ -0,0 +1,21 @@ +import React from 'react' +import { useRouter } from 'next/router' +import get from 'lodash/get' + +const useIsChromeExt = (): { isChromeExt: boolean; isSentFromWeb: boolean } => { + const router = useRouter() + const hideMenuQueryParam = get(router, 'query.hideMenu', '') + const isSentFromWeb = !!get(router, 'query.fromWeb', '') + const isChromeExt = !!(hideMenuQueryParam || (process.browser && (window as any).hideMenu)) + + React.useEffect(() => { + if (hideMenuQueryParam) { + // eslint-disable-next-line @typescript-eslint/no-extra-semi + ;(window as any).hideMenu = true + } + }, [hideMenuQueryParam]) + + return { isChromeExt, isSentFromWeb } +} + +export default useIsChromeExt diff --git a/misc/useSendTransaction.ts b/misc/useSendTransaction.ts new file mode 100644 index 00000000..61d4df8c --- /dev/null +++ b/misc/useSendTransaction.ts @@ -0,0 +1,39 @@ +import React from 'react' +import invoke from 'lodash/invoke' +import qs from 'query-string' +import { useRouter } from 'next/router' +import useIsChromeExt from './useIsChromeExt' + +const useSendTransaction = (): (( + password: string, + address: string, + tx: { msgs: TransactionMsg[]; memo: string } +) => Promise) => { + const router = useRouter() + const { isChromeExt } = useIsChromeExt() + + const sendTransaction = React.useCallback( + async ( + password: string, + address: string, + transactionData: { msgs: TransactionMsg[]; memo: string } + ) => { + if (isChromeExt) { + const { url, query: currentQuery } = qs.parseUrl(router.asPath) + const query = { + ...currentQuery, + password, + address, + transactionData: JSON.stringify(transactionData), + } + router.push(qs.stringifyUrl({ url, query })) + } else { + await invoke(window, 'forboleX.sendTransaction', password, address, transactionData) + } + }, + [isChromeExt, router] + ) + return sendTransaction +} + +export default useSendTransaction diff --git a/package.json b/package.json index 2ea3dc52..71219352 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "forbole-x", - "version": "0.7.0", + "version": "0.7.1", "private": true, "scripts": { "dev": "next dev", @@ -28,6 +28,7 @@ "graphql": "^15.5.0", "isomorphic-ws": "^4.0.1", "lodash": "^4.17.21", + "markdown-to-jsx": "^7.1.3", "next": "^11.1.1", "next-translate": "^1.0.1", "nodemailer": "^6.6.3", diff --git a/pages/address-book.tsx b/pages/address-book.tsx index eb1b5f3f..c883fe1d 100644 --- a/pages/address-book.tsx +++ b/pages/address-book.tsx @@ -1,12 +1,14 @@ import React from 'react' -import { Box, Button, Typography } from '@material-ui/core' +import { Box, Button, Typography, useTheme } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import Layout from '../components/Layout' import AddressBookTable from '../components/AddressBook' import AddAddressDialog from '../components/AddAddressDialog' +import { CustomTheme } from '../misc/theme' const AddressBook: React.FC = () => { const { t } = useTranslation('common') + const theme: CustomTheme = useTheme() const [addAddressOpen, setAddAddressOpen] = React.useState(false) return ( @@ -14,7 +16,12 @@ const AddressBook: React.FC = () => { {t('address book')} - diff --git a/pages/settings/index.tsx b/pages/settings/index.tsx index 7564e6c5..0a46cf31 100644 --- a/pages/settings/index.tsx +++ b/pages/settings/index.tsx @@ -2,11 +2,11 @@ import React from 'react' import { Box, IconButton, Typography, useTheme } from '@material-ui/core' import useTranslation from 'next-translate/useTranslation' import { useRouter } from 'next/router' -import get from 'lodash/get' import BackIcon from '../../assets/images/icons/icon_back.svg' import Layout from '../../components/Layout' import SettingTable from '../../components/SettingTable' import useIconProps from '../../misc/useIconProps' +import useIsChromeExt from '../../misc/useIsChromeExt' const Setting: React.FC = () => { const { t } = useTranslation('common') @@ -14,8 +14,7 @@ const Setting: React.FC = () => { const iconProps = useIconProps(3, theme.palette.grey[900]) // Show back btn for chrome extension const router = useRouter() - const hideMenuQueryParam = get(router, 'query.hideMenu', '') - const isChromeExt = hideMenuQueryParam || (process.browser && (window as any).hideMenu) + const { isChromeExt } = useIsChromeExt() return ( diff --git a/yarn.lock b/yarn.lock index 5c36a873..f2f500d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6526,6 +6526,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +markdown-to-jsx@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.1.3.tgz#f00bae66c0abe7dd2d274123f84cb6bd2a2c7c6a" + integrity sha512-jtQ6VyT7rMT5tPV0g2EJakEnXLiPksnvlYtwQsVVZ611JsWGN8bQ1tVSDX4s6JllfEH6wmsYxNjTUAMrPmNA8w== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"