diff --git a/packages/neuron-ui/src/components/CellManage/hooks.ts b/packages/neuron-ui/src/components/CellManage/hooks.ts index ed4edc243a..1db6a9d587 100644 --- a/packages/neuron-ui/src/components/CellManage/hooks.ts +++ b/packages/neuron-ui/src/components/CellManage/hooks.ts @@ -30,20 +30,22 @@ const getLockStatusAndReason = (item: State.LiveCellWithLocalInfo) => { locked: true, } } - let lockedReason = '' + let lockedReason: { key: string; params?: Record } | undefined if (item.typeScriptType) { switch (item.typeScriptType) { case TypeScriptCategory.NFT: case TypeScriptCategory.NFTClass: case TypeScriptCategory.NFTIssuer: - case TypeScriptCategory.Unknown: - lockedReason = 'cell-manage.locked-reason.operate-in-special-assets' + lockedReason = { key: 'cell-manage.locked-reason.NFT-SUDT-DAO', params: { type: 'NTF' } } break case TypeScriptCategory.SUDT: - lockedReason = 'cell-manage.locked-reason.operate-in-assets-account' + lockedReason = { key: 'cell-manage.locked-reason.NFT-SUDT-DAO', params: { type: 'SUDT' } } break case TypeScriptCategory.DAO: - lockedReason = 'cell-manage.locked-reason.operate-in-dao' + lockedReason = { key: 'cell-manage.locked-reason.NFT-SUDT-DAO', params: { type: 'Nervos DAO' } } + break + case TypeScriptCategory.Unknown: + lockedReason = { key: 'cell-manage.locked-reason.Unknown' } break default: break @@ -51,12 +53,16 @@ const getLockStatusAndReason = (item: State.LiveCellWithLocalInfo) => { } else { switch (item.lockScriptType) { case LockScriptCategory.Cheque: + lockedReason = { key: 'cell-manage.locked-reason.cheque-acp-multisig', params: { type: 'Cheque' } } + break case LockScriptCategory.ANYONE_CAN_PAY: - case LockScriptCategory.MULTI_LOCK_TIME: - lockedReason = 'cell-manage.locked-reason.operate-in-special-assets' + lockedReason = { key: 'cell-manage.locked-reason.cheque-acp-multisig', params: { type: 'Acp' } } break case LockScriptCategory.MULTISIG: - lockedReason = 'cell-manage.locked-reason.operate-in-multisig' + lockedReason = { key: 'cell-manage.locked-reason.cheque-acp-multisig', params: { type: 'Multisig' } } + break + case LockScriptCategory.MULTI_LOCK_TIME: + lockedReason = { key: 'cell-manage.locked-reason.multi-locktime' } break default: break diff --git a/packages/neuron-ui/src/components/CellManage/index.tsx b/packages/neuron-ui/src/components/CellManage/index.tsx index 41d8e6bfee..28718976be 100644 --- a/packages/neuron-ui/src/components/CellManage/index.tsx +++ b/packages/neuron-ui/src/components/CellManage/index.tsx @@ -14,6 +14,8 @@ import { useCopy, clsx, outPointToStr, + LockScriptCategory, + getLockTimestamp, } from 'utils' import { HIDE_BALANCE } from 'utils/const' import Tooltip from 'widgets/Tooltip' @@ -34,6 +36,8 @@ const getColumns = ({ selectedOutPoints, onSelectAll, onSelect, + epoch, + bestKnownBlockTimestamp, }: { updateLiveCell: (params: State.UpdateLiveCellLocalInfo) => void t: TFunction @@ -42,6 +46,8 @@ const getColumns = ({ selectedOutPoints: Set onSelectAll: (e: React.ChangeEvent) => void onSelect: (e: React.ChangeEvent) => void + epoch: string + bestKnownBlockTimestamp: number }): TableProps['columns'] => { return [ { @@ -109,11 +115,24 @@ const getColumns = ({ render(_, __, item: State.LiveCellWithLocalInfo) { const { locked, lockedReason } = item if (locked) { + let params = lockedReason?.params + if (item.lockScriptType === LockScriptCategory.MULTI_LOCK_TIME) { + if (bestKnownBlockTimestamp) { + const targetTime = new Date( + getLockTimestamp({ lockArgs: item.lock.args, epoch, bestKnownBlockTimestamp }) + ) + params = { + time: `${targetTime.getFullYear()}-${targetTime.getMonth() + 1}-${targetTime.getDate()}`, + } + } else { + params = { time: '--' } + } + } return (
{t('cell-manage.table.locked')} {lockedReason ? ( - + ) : null} @@ -188,8 +207,12 @@ const getColumns = ({ const CellManage = () => { const { + app: { epoch }, wallet: { balance = '' }, - chain: { networkID }, + chain: { + networkID, + syncState: { bestKnownBlockTimestamp }, + }, settings: { networks }, } = useGlobalState() const isMainnet = isMainnetUtil(networks, networkID) @@ -231,8 +254,20 @@ const CellManage = () => { onSelectAll, isAllSelected, selectedOutPoints, + epoch, + bestKnownBlockTimestamp, }), - [updateLiveCell, t, onOpenActionDialog, onSelect, onSelectAll, isAllSelected, selectedOutPoints] + [ + updateLiveCell, + t, + onOpenActionDialog, + onSelect, + onSelectAll, + isAllSelected, + selectedOutPoints, + epoch, + bestKnownBlockTimestamp, + ] ) const { copied, onCopy, copyTimes } = useCopy() const { onViewDetail, rawData, rawLock, rawType, usedCapacity } = useViewCell({ diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index dd5bed6fcd..d767ca8ce0 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -1174,10 +1174,10 @@ "used": "Used" }, "locked-reason": { - "operate-in-special-assets": "Please use in special assets page", - "operate-in-assets-account": "Please use in assets account page", - "operate-in-dao": "Please use in Nervos DAO page", - "operate-in-multisig": "Please use in multisig page" + "multi-locktime": "The cell has a time lock and you can't use it until {{time}}.", + "cheque-acp-multisig": "This is a {{type}} cell and does not support unlocking.", + "NFT-SUDT-DAO": " This is a {{type}} asset and does not support unlocking.", + "Unknown": "This is an uncataloged asset,please check and confirm before proceeding." }, "cell-lock-dialog": { "title": "Lock Cell", diff --git a/packages/neuron-ui/src/locales/zh-tw.json b/packages/neuron-ui/src/locales/zh-tw.json index 49b765ab6c..5c993c812b 100644 --- a/packages/neuron-ui/src/locales/zh-tw.json +++ b/packages/neuron-ui/src/locales/zh-tw.json @@ -1145,10 +1145,10 @@ "used": "已用" }, "locked-reason": { - "operate-in-special-assets": "請在自定義資產操作", - "operate-in-assets-account": "請在資產賬戶操作", - "operate-in-dao": "請在 Nervos DAO 操作", - "operate-in-multisig": "請在多簽地址操作" + "multi-locktime": "The cell has a time lock and you can't use it until {{time}}.", + "cheque-acp-multisig": "這是壹個 {{type}} 的 cell, 不支持解鎖。", + "NFT-SUDT-DAO": "這是壹個 {{type}} 的資產,不支持解鎖。", + "Unknown": "This is an uncataloged asset,please check and confirm before proceeding." }, "cell-lock-dialog": { "title": "鎖定 Cell", diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index cf53d78b80..436ee7dbb3 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -1166,10 +1166,10 @@ "used": "已用" }, "locked-reason": { - "operate-in-special-assets": "请在自定义资产操作", - "operate-in-assets-account": "请在资产账户操作", - "operate-in-dao": "请在 Nervos DAO 操作", - "operate-in-multisig": "请在多签地址操作" + "multi-locktime": "The cell has a time lock and you can't use it until {{time}}。", + "cheque-acp-multisig": "这是一个 {{type}} 的 cell, 不支持解锁。", + "NFT-SUDT-DAO": "这是一个 {{type}} 的资产,不支持解锁。", + "Unknown": "這是壹項未知的資產,請在繼續操作之前進行檢查和確認。" }, "cell-lock-dialog": { "title": "锁定 Cell", diff --git a/packages/neuron-ui/src/types/App/index.d.ts b/packages/neuron-ui/src/types/App/index.d.ts index 02d08b59b2..28f1f90cd5 100644 --- a/packages/neuron-ui/src/types/App/index.d.ts +++ b/packages/neuron-ui/src/types/App/index.d.ts @@ -365,7 +365,7 @@ declare namespace State { locked?: boolean } interface LiveCellWithLocalInfo extends LiveCellWithLocalInfoAPI { - lockedReason?: string + lockedReason?: { key: string; params?: Record } cellType?: 'CKB' | 'SUDT' | 'NFT' | 'Unknown' } diff --git a/packages/neuron-ui/src/utils/parsers.ts b/packages/neuron-ui/src/utils/parsers.ts index cfad394fe1..6a4ac02b95 100644 --- a/packages/neuron-ui/src/utils/parsers.ts +++ b/packages/neuron-ui/src/utils/parsers.ts @@ -1,5 +1,5 @@ import { toUint64Le, parseEpoch } from 'services/chain' -import { PAGE_SIZE } from './const' +import { MILLISECONDS, PAGE_SIZE } from './const' export const listParams = (search: string) => { const query = new URLSearchParams(search) @@ -44,3 +44,23 @@ export const toUint128Le = (hexString: string) => { return `${toUint64Le(`0x${s.substr(18, 16)}`)}${toUint64Le(s.substr(0, 18)).slice(2)}` } + +export const getLockTimestamp = ({ + lockArgs, + epoch, + bestKnownBlockTimestamp, +}: { + lockArgs: string + epoch: string + bestKnownBlockTimestamp: number +}) => { + const targetEpochInfo = epochParser(toUint64Le(`0x${lockArgs.slice(-16)}`)) + const currentEpochInfo = epochParser(epoch) + const targetEpochFraction = + Number(targetEpochInfo.length) > 0 ? Number(targetEpochInfo.index) / Number(targetEpochInfo.length) : 1 + const epochsInfo = { + target: Number(targetEpochInfo.number) + Math.min(targetEpochFraction, 1), + current: Number(currentEpochInfo.number) + Number(currentEpochInfo.index) / Number(currentEpochInfo.length), + } + return bestKnownBlockTimestamp + (epochsInfo.target - epochsInfo.current) * MILLISECONDS +}