Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Hot/cold combination of a wallet doesn't work smooth #3000

Merged
merged 15 commits into from
Jan 29, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.main {
tr {
td {
font-size: 14px;
line-height: 26px;
color: var(--main-text-color);
svg {
width: 14px;
height: 14px;
margin-right: 4px;
position: relative;
top: 2px;
}
}
.first {
padding-right: 24px;
color: var(--input-second-color);
}
}
}

.warningDialog {
width: 680px;
.content {
display: flex;
justify-content: center;
margin-top: 24px;
color: var(--main-text-color);
}
}

.textarea {
color: var(--main-text-color);
margin-top: 17px;
width: 648px;
height: 206px;
resize: none;
background: var(--secondary-background-color);
border: 1px solid var(--divide-line-color);
border-radius: 8px;
padding: 16px;
}
124 changes: 124 additions & 0 deletions packages/neuron-ui/src/components/BroadcastTransaction/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { isSuccessResponse, RoutePath, useDidMount, useGoBack } from 'utils'
import Dialog from 'widgets/Dialog'
import AlertDialog from 'widgets/AlertDialog'
import { useDispatch, useState as useGlobalState } from 'states'
import { broadcastTransaction, getCurrentWallet, OfflineSignStatus } from 'services/remote'
import { ReactComponent as HardWalletIcon } from 'widgets/Icons/HardWallet.svg'

import styles from './broadcastTransaction.module.scss'

const BroadcastTransaction = () => {
const {
app: { loadedTransaction = {} },
} = useGlobalState()

const [wallet, setWallet] = useState<State.Wallet | null>(null)
devchenyan marked this conversation as resolved.
Show resolved Hide resolved
const [isBroadCasting, setIsBroadcasting] = useState(false)
Keith-CY marked this conversation as resolved.
Show resolved Hide resolved
const [t] = useTranslation()
const dispatch = useDispatch()
const [errMsg, setErrMsg] = useState('')

const { filePath, json } = loadedTransaction

const jsonContent = useMemo(() => {
return JSON.stringify(json, null, 2)
}, [json])

const signStatus: OfflineSignStatus = json.status

const isSigned = useMemo(() => signStatus === OfflineSignStatus.Signed, [signStatus])

const onBack = useGoBack()

const navigate = useNavigate()
const onBroadcast = useCallback(async () => {
setIsBroadcasting(true)
try {
const res = await broadcastTransaction({
...json,
walletID: wallet!.id,
Keith-CY marked this conversation as resolved.
Show resolved Hide resolved
})
if (isSuccessResponse(res)) {
navigate(RoutePath.History)
Keith-CY marked this conversation as resolved.
Show resolved Hide resolved
} else {
setErrMsg(typeof res.message === 'string' ? res.message : res.message.content || '')
}
} finally {
setIsBroadcasting(false)
}
}, [wallet, json, navigate, dispatch])

useDidMount(() => {
getCurrentWallet().then(res => {
devchenyan marked this conversation as resolved.
Show resolved Hide resolved
if (isSuccessResponse(res)) {
setWallet(res.result)
}
})
})

return (
<>
<Dialog
show={isSigned}
title={t('offline-sign.broadcast-transaction')}
cancelText={t('offline-sign.actions.cancel')}
onCancel={onBack}
confirmText={t('offline-sign.actions.broadcast')}
isLoading={isBroadCasting}
onConfirm={onBroadcast}
>
<div className={styles.main}>
<table>
<tbody>
<tr>
<td className={styles.first}>{t('offline-sign.json-file')}</td>
<td>{filePath}</td>
</tr>
<tr>
<td className={styles.first}>{t('offline-sign.status.label')}</td>
<td>{t('offline-sign.status.signed')}</td>
</tr>
<tr>
<td className={styles.first}>{t('offline-sign.wallet')}</td>
<td>
{wallet?.device ? <HardWalletIcon /> : null}
<span>{wallet?.name ?? ''}</span>
</td>
</tr>
<tr>
<td className={styles.first}>{t('offline-sign.content')}</td>
</tr>
</tbody>
</table>
<textarea disabled value={jsonContent} className={styles.textarea} />
</div>
</Dialog>

<Dialog
show={!isSigned}
className={styles.warningDialog}
title={t('offline-sign.import-unsigned-transaction')}
cancelText={t('offline-sign.actions.cancel')}
onCancel={onBack}
onConfirm={onBack}
>
<div className={styles.content}>{t('offline-sign.import-unsigned-transaction-detail')}</div>
</Dialog>

<AlertDialog
show={!!errMsg}
title={t('message-types.alert')}
message={errMsg}
type="failed"
onCancel={() => setErrMsg('')}
/>
</>
)
}

BroadcastTransaction.displayName = 'BroadcastTransaction'

export default BroadcastTransaction
60 changes: 28 additions & 32 deletions packages/neuron-ui/src/components/OfflineSign/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { isSuccessResponse, RoutePath, useDidMount, useGoBack } from 'utils'
import { isSuccessResponse, useDidMount, useGoBack } from 'utils'
import Dialog from 'widgets/Dialog'
import AlertDialog from 'widgets/AlertDialog'
import { useDispatch, useState as useGlobalState } from 'states'
import { broadcastTransaction, getCurrentWallet, OfflineSignStatus } from 'services/remote'
import { useState as useGlobalState } from 'states'
import { getCurrentWallet, OfflineSignStatus } from 'services/remote'
import { ReactComponent as HardWalletIcon } from 'widgets/Icons/HardWallet.svg'
import OfflineSignDialog from '../OfflineSignDialog'

Expand All @@ -18,9 +17,7 @@ const OfflineSign = () => {

const [wallet, setWallet] = useState<State.Wallet | null>(null)
const [isSigning, setIsSigning] = useState(false)
const [isBroadCasting, setIsBroadcasting] = useState(false)
const [t] = useTranslation()
const dispatch = useDispatch()
const [errMsg, setErrMsg] = useState('')

const { filePath, json } = loadedTransaction
Expand All @@ -31,6 +28,8 @@ const OfflineSign = () => {

const signStatus: OfflineSignStatus = json.status

const isSigned = useMemo(() => signStatus === OfflineSignStatus.Signed, [signStatus])

const status = useMemo(() => {
switch (signStatus) {
case OfflineSignStatus.Unsigned:
Expand All @@ -48,24 +47,6 @@ const OfflineSign = () => {
setIsSigning(true)
}, [setIsSigning])

const navigate = useNavigate()
const onBroadcast = useCallback(async () => {
setIsBroadcasting(true)
try {
const res = await broadcastTransaction({
...json,
walletID: wallet!.id,
})
if (isSuccessResponse(res)) {
navigate(RoutePath.History)
} else {
setErrMsg(typeof res.message === 'string' ? res.message : res.message.content || '')
}
} finally {
setIsBroadcasting(false)
}
}, [wallet, json, navigate, dispatch])

useDidMount(() => {
getCurrentWallet().then(res => {
if (isSuccessResponse(res)) {
Expand All @@ -76,26 +57,29 @@ const OfflineSign = () => {

const signDialogOnDismiss = useCallback(() => {
setIsSigning(false)
}, [])
}, [setIsSigning])

if (isSigning && wallet) {
return (
<OfflineSignDialog isBroadcast={false} wallet={wallet} offlineSignJSON={json} onDismiss={signDialogOnDismiss} />
<OfflineSignDialog
isBroadcast={false}
wallet={wallet}
offlineSignJSON={json}
onDismiss={signDialogOnDismiss}
onCompleted={onBack}
/>
)
}

return (
<>
<Dialog
show={!isSigning}
show={!isSigned}
title={t('offline-sign.title')}
cancelText={t('offline-sign.actions.cancel')}
onCancel={onBack}
confirmText={
signStatus === OfflineSignStatus.Signed ? t('offline-sign.actions.broadcast') : t('offline-sign.actions.sign')
}
isLoading={signStatus === OfflineSignStatus.Signed && isBroadCasting}
onConfirm={signStatus === OfflineSignStatus.Signed ? onBroadcast : onSign}
confirmText={t('offline-sign.actions.sign')}
onConfirm={onSign}
>
<div className={styles.main}>
<table>
Expand Down Expand Up @@ -123,6 +107,18 @@ const OfflineSign = () => {
<textarea disabled value={jsonContent} className={styles.textarea} />
</div>
</Dialog>

<Dialog
show={isSigned}
className={styles.warningDialog}
title={t('offline-sign.import-signed-transaction')}
cancelText={t('offline-sign.actions.cancel')}
onCancel={onBack}
onConfirm={onBack}
>
<div className={styles.content}>{t('offline-sign.import-signed-transaction-detail')}</div>
</Dialog>

<AlertDialog
show={!!errMsg}
title={t('message-types.alert')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@
}
}

.warningDialog {
width: 680px;
.content {
display: flex;
justify-content: center;
margin-top: 24px;
color: var(--main-text-color);
}
}

.textarea {
color: var(--main-text-color);
margin-top: 17px;
Expand Down
7 changes: 4 additions & 3 deletions packages/neuron-ui/src/components/OfflineSignDialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ interface SignDialogProps {
wallet: State.Wallet
offlineSignJSON: OfflineSignJSON
onDismiss: () => void
onCompleted: () => void
}

const OfflineSignDialog = ({ isBroadcast, wallet, offlineSignJSON, onDismiss }: SignDialogProps) => {
const OfflineSignDialog = ({ isBroadcast, wallet, offlineSignJSON, onDismiss, onCompleted }: SignDialogProps) => {
const {
app: {
send: { description },
Expand Down Expand Up @@ -65,8 +66,8 @@ const OfflineSignDialog = ({ isBroadcast, wallet, offlineSignJSON, onDismiss }:
type: AppActions.UpdateLoadedTransaction,
payload: res.result!,
})
onDismiss()
}, [offlineSignJSON, dispatch, onDismiss, t, password, walletID])
onCompleted()
}, [offlineSignJSON, dispatch, onCompleted, t, password, walletID])

const onSubmit = useCallback(
async (e?: React.FormEvent) => {
Expand Down
7 changes: 6 additions & 1 deletion packages/neuron-ui/src/locales/en.json
devchenyan marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@
"partially-signed": "Partially Signed",
"signed": "Signed"
},
"import-signed-transaction": "Import signed transaction",
Keith-CY marked this conversation as resolved.
Show resolved Hide resolved
"import-signed-transaction-detail": "You have imported a signed transaction, please confirm and try again.",
"wallet": "Wallet:",
"content": "Content:",
"export": "Export Tx",
Expand All @@ -121,7 +123,10 @@
"broadcast": "Broadcast",
"sign": "Sign and export",
"cancel": "Cancel"
}
},
"broadcast-transaction": "Broadcast Transaction",
"import-unsigned-transaction": "Import unsigned transaction",
"import-unsigned-transaction-detail": "You have imported a unsigned transaction, please confirm and try again."
Keith-CY marked this conversation as resolved.
Show resolved Hide resolved
},
"overview": {
"date": "Date",
Expand Down
7 changes: 6 additions & 1 deletion packages/neuron-ui/src/locales/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@
"partially-signed": "部分簽名",
"signed": "已簽名"
},
"import-signed-transaction": "導入已簽名交易",
"import-signed-transaction-detail": "您導入了一個已簽名交易,請確認並重試。",
"wallet": "錢包:",
"content": "內容:",
"export": "導出交易",
Expand All @@ -115,7 +117,10 @@
"broadcast": "廣播交易",
"sign": "簽名並導出",
"cancel": "取消"
}
},
"broadcast-transaction": "廣播交易",
"import-unsigned-transaction": "導入未簽名交易",
"import-unsigned-transaction-detail": "您導入了一個未簽名交易,請確認並重試。"
},
"overview": {
"date": "時間",
Expand Down
7 changes: 6 additions & 1 deletion packages/neuron-ui/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
"partially-signed": "部分签名",
"signed": "已签名"
},
"import-signed-transaction": "导入已签名交易",
"import-signed-transaction-detail": "您导入了一个已签名交易,请确认并重试。",
"wallet": "钱包:",
"content": "内容:",
"export": "导出交易",
Expand All @@ -114,7 +116,10 @@
"broadcast": "广播交易",
"sign": "签名并导出",
"cancel": "取消"
}
},
"broadcast-transaction": "广播交易",
"import-unsigned-transaction": "导入未签名",
"import-unsigned-transaction-detail": "您导入了一个未签名交易,请确认并重试。"
},
"overview": {
"date": "时间",
Expand Down
Loading