From 6d3b3db7692e1baaaa344d629fb563dbfb65f017 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Thu, 7 Jul 2022 12:02:08 +0800 Subject: [PATCH 01/23] feat: SCAN-4201, add user profile import and export --- src/app/components/Card/index.tsx | 16 ++- src/app/components/FileUpload/Loadable.ts | 12 -- src/app/containers/Profile/File.tsx | 168 ++++++++++++++++++++++ src/app/containers/Profile/TxNote.tsx | 2 +- src/app/containers/Profile/index.tsx | 92 +++++++++++- src/app/index.tsx | 3 + src/locales/en/translation.json | 19 +++ src/locales/zh_cn/translation.json | 19 +++ 8 files changed, 309 insertions(+), 22 deletions(-) delete mode 100644 src/app/components/FileUpload/Loadable.ts create mode 100644 src/app/containers/Profile/File.tsx diff --git a/src/app/components/Card/index.tsx b/src/app/components/Card/index.tsx index 95bc06bcc..9176584ac 100644 --- a/src/app/components/Card/index.tsx +++ b/src/app/components/Card/index.tsx @@ -3,18 +3,22 @@ import { Card as UICard } from '@cfxjs/react-ui'; import styled from 'styled-components/macro'; import { CardProps } from '@cfxjs/react-ui/dist/card/card'; import clsx from 'clsx'; +import { Spin } from '@cfxjs/antd'; export const Card = ({ children, className, + loading = false, ...others -}: Partial) => { +}: Partial & { loading?: boolean }) => { return ( - - - {children} - - + + + + {children} + + + ); }; diff --git a/src/app/components/FileUpload/Loadable.ts b/src/app/components/FileUpload/Loadable.ts deleted file mode 100644 index 8cf666f47..000000000 --- a/src/app/components/FileUpload/Loadable.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * - * Asynchronously loads the component for FileUpload - * - */ - -import { lazyLoad } from 'utils/loadable'; - -export const FileUpload = lazyLoad( - () => import('./index'), - module => module.FileUpload, -); diff --git a/src/app/containers/Profile/File.tsx b/src/app/containers/Profile/File.tsx new file mode 100644 index 000000000..53444037c --- /dev/null +++ b/src/app/containers/Profile/File.tsx @@ -0,0 +1,168 @@ +import React, { createRef } from 'react'; +import { FileUpload } from 'app/components/FileUpload'; +import { LOCALSTORAGE_KEYS_MAP } from 'utils/constants'; +import { useGlobalData } from 'utils/hooks/useGlobal'; +import lodash from 'lodash'; +import { InfoIconWithTooltip } from 'app/components/InfoIconWithTooltip/Loadable'; +import styled from 'styled-components/macro'; +import { useTranslation } from 'react-i18next'; +import { translations } from 'locales/i18n'; +import { message } from '@cfxjs/antd'; + +interface Props { + onLoading?: (loading: boolean) => void; +} +export const File = ({ onLoading = () => {} }: Props) => { + const [globalData, setGlobalData] = useGlobalData(); + const inputRef = createRef(); + const { t } = useTranslation(); + + const handleImport = () => { + inputRef.current.click(); + }; + + const handleFileChange = file => { + try { + onLoading(true); + + let { txPrivateNotes, addressNameTags } = JSON.parse(file); + + if (addressNameTags !== null && addressNameTags.length > 0) { + const oldTags = localStorage.getItem( + LOCALSTORAGE_KEYS_MAP.addressLabel, + ); + const oldList = oldTags ? JSON.parse(oldTags) : []; + + // New imports have higher priority + const tags = lodash + .unionBy(addressNameTags, oldList, 'a') + .sort((a, b) => b.u - a.u); + + localStorage.setItem( + LOCALSTORAGE_KEYS_MAP.addressLabel, + JSON.stringify(tags), + ); + setGlobalData({ + ...globalData, + [LOCALSTORAGE_KEYS_MAP.addressLabel]: tags.reduce((prev, curr) => { + return { + ...prev, + [curr.a]: curr.l, + }; + }, {}), + }); + + message.info( + t(translations.profile.file.import.address, { + amount: tags.length - oldList.length, + }), + ); + } + + if (txPrivateNotes !== null && txPrivateNotes.length > 0) { + const oldNotes = localStorage.getItem( + LOCALSTORAGE_KEYS_MAP.txPrivateNote, + ); + const oldList = oldNotes ? JSON.parse(oldNotes) : []; + // New imports have higher priority + const notes = lodash + .unionBy(txPrivateNotes, oldList, 'h') + .sort((a, b) => b.u - a.u); + + localStorage.setItem( + LOCALSTORAGE_KEYS_MAP.txPrivateNote, + JSON.stringify(notes), + ); + setGlobalData({ + ...globalData, + [LOCALSTORAGE_KEYS_MAP.txPrivateNote]: notes.reduce((prev, curr) => { + return { + ...prev, + [curr.h]: curr.n, + }; + }, {}), + }); + + message.info( + t(translations.profile.file.import.tx, { + amount: notes.length - oldList.length, + }), + ); + } + } catch (e) { + console.log(e); + message.error(t(translations.profile.file.error.invalid)); + } + + onLoading(false); + }; + + const handleFileError = () => { + message.error(t(translations.profile.file.error.invalid)); + }; + + const handleExport = () => { + onLoading(true); + + try { + const notes = localStorage.getItem(LOCALSTORAGE_KEYS_MAP.txPrivateNote); + const tags = localStorage.getItem(LOCALSTORAGE_KEYS_MAP.addressLabel); + const data = { + txPrivateNotes: notes ? JSON.parse(notes) : null, + addressNameTags: tags ? JSON.parse(tags) : null, + }; + const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( + JSON.stringify(data), + )}`; + + const link = document.createElement('a'); + link.href = jsonString; + link.download = 'data.json'; + link.click(); + } catch (e) { + message.error(t(translations.profile.file.export.failed)); + } + + message.info(t(translations.profile.file.export.complete)); + + onLoading(false); + }; + + return ( +
+ + + + + {t(translations.profile.file.import.button)} + + + / + + + {t(translations.profile.file.export.button)} + + + +
+ ); +}; + +const StyledFileManagementWrapper = styled.div` + margin-top: 100px; + text-align: right; + + .button { + color: #1e3de4; + cursor: pointer; + + &:hover { + color: #0f23bd; + } + } +`; diff --git a/src/app/containers/Profile/TxNote.tsx b/src/app/containers/Profile/TxNote.tsx index a68005f79..c34afb4be 100644 --- a/src/app/containers/Profile/TxNote.tsx +++ b/src/app/containers/Profile/TxNote.tsx @@ -59,7 +59,7 @@ export function TxNote() { title: t(translations.profile.tx.hash), dataIndex: 'h', key: 'h', - width: 8, + width: 9, render(v) { return ( diff --git a/src/app/containers/Profile/index.tsx b/src/app/containers/Profile/index.tsx index 7e80cdef5..afb38d45d 100644 --- a/src/app/containers/Profile/index.tsx +++ b/src/app/containers/Profile/index.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { TabsTablePanel } from 'app/components/TabsTablePanel/Loadable'; +import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { translations } from 'locales/i18n'; import styled from 'styled-components/macro'; @@ -7,9 +6,17 @@ import { Helmet } from 'react-helmet-async'; import { PageHeader } from 'app/components/PageHeader/Loadable'; import { AddressLabel } from './AddressLabel'; import { TxNote } from './TxNote'; +import { File } from './File'; +import { Row, Col } from '@cfxjs/antd'; +import { Card } from 'app/components/Card/Loadable'; +import { useLocation, useHistory } from 'react-router-dom'; +import qs from 'query-string'; export function Profile() { + const { search } = useLocation(); + const history = useHistory(); const { t } = useTranslation(); + const [loading, setLoading] = useState(false); const tabs = [ { value: 'address-label', @@ -22,6 +29,17 @@ export function Profile() { content: , }, ]; + const { tab = 'address-label' } = qs.parse(search); + const activeTab = tabs.filter(t => t.value === tab)?.[0] || tabs[0]; + + const handleClick = (_, key) => { + history.push(`/profile?tab=${key}`); + }; + + const handleLoading = loading => { + setLoading(loading); + }; + return ( @@ -31,7 +49,30 @@ export function Profile() { {t(translations.profile.title)} - + + + + + {tabs.map(t => ( +
handleClick(e, t.value)} + > + {t.label} +
+ ))} + + +
+
+ + + + {activeTab.content} + + +
); } @@ -42,4 +83,49 @@ const StyledWrapper = styled.div` align-items: center; justify-content: space-between; } + + .card.sirius-card { + padding: 1rem; + } +`; + +const StyledNavWrapper = styled.div` + margin-bottom: 24px; + .nav { + display: flex; + align-items: center; + height: 42px; + margin: 8px 0; + border-radius: 4px; + background: #fff; + transition: background 0.25s; + padding: 12px; + + .card.sirius-card { + padding: 0; + } + + &:hover { + background: #eee; + cursor: pointer; + } + + &.active { + background: #eee; + } + + &:last-child { + margin-bottom: 8px; + } + } +`; +const StyledContentWrapper = styled.div` + .ant-table-wrapper.shadowed div.ant-table { + padding: 0; + box-shadow: none; + } + + ul.ant-table-pagination.ant-pagination { + margin-bottom: 0; + } `; diff --git a/src/app/index.tsx b/src/app/index.tsx index e23d10e93..f424179eb 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -131,6 +131,9 @@ import moment from 'moment'; import { ConfigProvider } from '@cfxjs/antd'; import 'moment/locale/zh-cn'; +// @ts-ignore +window.lodash = lodash; + // WebFontLoader.load({ // custom: { // families: ['Circular Std:n4,i4,n7,i7,n8,i8'], diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 5a6addf02..d1de7a6ce 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -37,6 +37,25 @@ }, "publicNameTag": "Public Tag: ", "myNameTag": "My Name Tag: " + }, + "file": { + "error": { + "invalid": "Invalid file" + }, + "export": { + "button": "Export", + "tip": "Export all user profile config data, include address name tags and transaction private notes", + "complete": "Export completed", + "failed": "Export Failed" + }, + "import": { + "button": "Import", + "tip": "Import all user profile config data, include address name tags and transaction private notes. If there is a configuration data conflict, the imported data overwrites the existing data", + "complete": "Import completed", + "failed": "Import failed", + "address": "Import {{amount}} address name tags", + "tx": "Import {{amount}} transaction private notes" + } } }, "metadata": { diff --git a/src/locales/zh_cn/translation.json b/src/locales/zh_cn/translation.json index 7f41caec1..2fe445c5f 100644 --- a/src/locales/zh_cn/translation.json +++ b/src/locales/zh_cn/translation.json @@ -37,6 +37,25 @@ }, "publicNameTag": "公共标签:", "myNameTag": "我的标签:" + }, + "file": { + "error": { + "invalid": "无效文件" + }, + "export": { + "button": "导出", + "tip": "导出所有用户个人资料配置数据,包括地址标签和交易备注", + "complete": "导出完成", + "failed": "导出失败" + }, + "import": { + "button": "导入", + "tip": "导入所有用户个人资料配置数据,包括地址标签和交易备注, 如果存在配置数据冲突,则导入数据覆盖已有数据", + "complete": "导入完成", + "failed": "导入失败", + "address": "导入 {{amount}} 条地址标签", + "tx": "导入 {{amount}} 条交易备注" + } } }, "metadata": { From 5028331c74718569e20530167642a3deab3426a1 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Thu, 7 Jul 2022 14:34:24 +0800 Subject: [PATCH 02/23] feat: update profile tip info --- src/app/containers/Profile/AddressLabel.tsx | 1 + src/app/containers/Profile/TxNote.tsx | 1 + src/locales/en/translation.json | 4 ++-- src/locales/zh_cn/translation.json | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/app/containers/Profile/AddressLabel.tsx b/src/app/containers/Profile/AddressLabel.tsx index a0e4ee749..c943b5f8d 100644 --- a/src/app/containers/Profile/AddressLabel.tsx +++ b/src/app/containers/Profile/AddressLabel.tsx @@ -242,6 +242,7 @@ export function AddressLabel() { loading={loading} rowKey="a" key={Math.random()} + scroll={{ x: 800 }} /> Date: Thu, 7 Jul 2022 14:57:13 +0800 Subject: [PATCH 03/23] feat: add max records check --- src/app/containers/Profile/File.tsx | 98 ++++++++++++++++++----------- src/locales/en/translation.json | 3 +- 2 files changed, 62 insertions(+), 39 deletions(-) diff --git a/src/app/containers/Profile/File.tsx b/src/app/containers/Profile/File.tsx index 53444037c..a0b08e6af 100644 --- a/src/app/containers/Profile/File.tsx +++ b/src/app/containers/Profile/File.tsx @@ -38,25 +38,35 @@ export const File = ({ onLoading = () => {} }: Props) => { .unionBy(addressNameTags, oldList, 'a') .sort((a, b) => b.u - a.u); - localStorage.setItem( - LOCALSTORAGE_KEYS_MAP.addressLabel, - JSON.stringify(tags), - ); - setGlobalData({ - ...globalData, - [LOCALSTORAGE_KEYS_MAP.addressLabel]: tags.reduce((prev, curr) => { - return { - ...prev, - [curr.a]: curr.l, - }; - }, {}), - }); - - message.info( - t(translations.profile.file.import.address, { - amount: tags.length - oldList.length, - }), - ); + if (tags.length > 1000) { + message.error( + t(translations.profile.tip.exceed, { + type: t(translations.profile.address.label), + amount: 1000, + }), + ); + } else { + localStorage.setItem( + LOCALSTORAGE_KEYS_MAP.addressLabel, + JSON.stringify(tags), + ); + + setGlobalData({ + ...globalData, + [LOCALSTORAGE_KEYS_MAP.addressLabel]: tags.reduce((prev, curr) => { + return { + ...prev, + [curr.a]: curr.l, + }; + }, {}), + }); + + message.info( + t(translations.profile.file.import.address, { + amount: tags.length - oldList.length, + }), + ); + } } if (txPrivateNotes !== null && txPrivateNotes.length > 0) { @@ -69,25 +79,37 @@ export const File = ({ onLoading = () => {} }: Props) => { .unionBy(txPrivateNotes, oldList, 'h') .sort((a, b) => b.u - a.u); - localStorage.setItem( - LOCALSTORAGE_KEYS_MAP.txPrivateNote, - JSON.stringify(notes), - ); - setGlobalData({ - ...globalData, - [LOCALSTORAGE_KEYS_MAP.txPrivateNote]: notes.reduce((prev, curr) => { - return { - ...prev, - [curr.h]: curr.n, - }; - }, {}), - }); - - message.info( - t(translations.profile.file.import.tx, { - amount: notes.length - oldList.length, - }), - ); + if (notes.length > 1000) { + message.error( + t(translations.profile.tip.exceed, { + type: t(translations.profile.tx.hash), + amount: 1000, + }), + ); + } else { + localStorage.setItem( + LOCALSTORAGE_KEYS_MAP.txPrivateNote, + JSON.stringify(notes), + ); + setGlobalData({ + ...globalData, + [LOCALSTORAGE_KEYS_MAP.txPrivateNote]: notes.reduce( + (prev, curr) => { + return { + ...prev, + [curr.h]: curr.n, + }; + }, + {}, + ), + }); + + message.info( + t(translations.profile.file.import.tx, { + amount: notes.length - oldList.length, + }), + ); + } } } catch (e) { console.log(e); diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 6b2b411f3..b16406d08 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -4,7 +4,8 @@ "subtitle": "Private info, like private name tag and transaction private note. Decentralized storage in browser's localstorage.", "tip": { "label": "Private name tag", - "note": "Private note to keep track of the transaction." + "note": "Private note to keep track of the transaction", + "exceed": "The {{type}} exceeds {{amount}} records, please delete some and try again" }, "tx": { "title": "Transaction Private Notes", From aba4ec7340bb8a5c7ac3a0af8568a6e4fb349d82 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Mon, 11 Jul 2022 10:48:48 +0800 Subject: [PATCH 04/23] feat: 1. add import update amount 2. update download file suffix --- src/app/containers/Profile/File.tsx | 29 ++++++++++++++++++++++++++--- src/locales/en/translation.json | 4 ++-- src/locales/zh_cn/translation.json | 4 ++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/app/containers/Profile/File.tsx b/src/app/containers/Profile/File.tsx index a0b08e6af..285c35b47 100644 --- a/src/app/containers/Profile/File.tsx +++ b/src/app/containers/Profile/File.tsx @@ -33,9 +33,19 @@ export const File = ({ onLoading = () => {} }: Props) => { ); const oldList = oldTags ? JSON.parse(oldTags) : []; + let updateAmount = 0; // New imports have higher priority const tags = lodash - .unionBy(addressNameTags, oldList, 'a') + .unionWith(addressNameTags, oldList, (arrVal, othVal) => { + if (arrVal.a === othVal.a) { + if (arrVal.l !== othVal.l) { + updateAmount += 1; + } + return true; + } else { + return false; + } + }) .sort((a, b) => b.u - a.u); if (tags.length > 1000) { @@ -64,6 +74,7 @@ export const File = ({ onLoading = () => {} }: Props) => { message.info( t(translations.profile.file.import.address, { amount: tags.length - oldList.length, + updateAmount, }), ); } @@ -74,9 +85,20 @@ export const File = ({ onLoading = () => {} }: Props) => { LOCALSTORAGE_KEYS_MAP.txPrivateNote, ); const oldList = oldNotes ? JSON.parse(oldNotes) : []; + + let updateAmount = 0; // New imports have higher priority const notes = lodash - .unionBy(txPrivateNotes, oldList, 'h') + .unionWith(txPrivateNotes, oldList, (arrVal, othVal) => { + if (arrVal.h === othVal.h) { + if (arrVal.n !== othVal.n) { + updateAmount += 1; + } + return true; + } else { + return false; + } + }) .sort((a, b) => b.u - a.u); if (notes.length > 1000) { @@ -107,6 +129,7 @@ export const File = ({ onLoading = () => {} }: Props) => { message.info( t(translations.profile.file.import.tx, { amount: notes.length - oldList.length, + updateAmount, }), ); } @@ -139,7 +162,7 @@ export const File = ({ onLoading = () => {} }: Props) => { const link = document.createElement('a'); link.href = jsonString; - link.download = 'data.json'; + link.download = 'confluxscan-user-profile.json'; link.click(); } catch (e) { message.error(t(translations.profile.file.export.failed)); diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index b16406d08..c5fe571db 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -54,8 +54,8 @@ "tip": "Import all user profile info, include address name tags and transaction private notes. If there is a configuration data conflict, the imported data overwrites the existing data", "complete": "Import completed", "failed": "Import failed", - "address": "Import {{amount}} address name tags", - "tx": "Import {{amount}} transaction private notes" + "address": "Import {{amount}} address name tags, update {{updateAmount}} address name tags", + "tx": "Import {{amount}} transaction private notes, update {{updateAmount}} transaction private notes" } } }, diff --git a/src/locales/zh_cn/translation.json b/src/locales/zh_cn/translation.json index 5909a3547..82e40a1c4 100644 --- a/src/locales/zh_cn/translation.json +++ b/src/locales/zh_cn/translation.json @@ -53,8 +53,8 @@ "tip": "导入所有用户私人信息,包括地址标签和交易备注, 如果存在配置数据冲突,则导入数据覆盖已有数据", "complete": "导入完成", "failed": "导入失败", - "address": "导入 {{amount}} 条地址标签", - "tx": "导入 {{amount}} 条交易备注" + "address": "导入 {{amount}} 条地址标签,更新 {{updateAmount}} 条地址标签", + "tx": "导入 {{amount}} 条交易备注,更新 {{updateAmount}} 条交易备注" } } }, From d69dd42b6cd9f22edf92ed16f35b79aa4e32a646 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Wed, 13 Jul 2022 16:26:14 +0800 Subject: [PATCH 05/23] feat: SCAN-4239 --- src/app/containers/Profile/File.tsx | 21 +++++++++++++++++++-- src/locales/en/translation.json | 3 ++- src/locales/zh_cn/translation.json | 3 ++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/app/containers/Profile/File.tsx b/src/app/containers/Profile/File.tsx index 285c35b47..4a4def788 100644 --- a/src/app/containers/Profile/File.tsx +++ b/src/app/containers/Profile/File.tsx @@ -8,6 +8,7 @@ import styled from 'styled-components/macro'; import { useTranslation } from 'react-i18next'; import { translations } from 'locales/i18n'; import { message } from '@cfxjs/antd'; +import MD5 from 'md5.js'; interface Props { onLoading?: (loading: boolean) => void; @@ -25,7 +26,15 @@ export const File = ({ onLoading = () => {} }: Props) => { try { onLoading(true); - let { txPrivateNotes, addressNameTags } = JSON.parse(file); + const { data, key } = JSON.parse(file); + + if (new MD5().update(JSON.stringify(data)).digest('hex') !== key) { + message.error(t(translations.profile.file.error.fileChanged)); + onLoading(false); + return; + } + + const { txPrivateNotes, addressNameTags } = data; if (addressNameTags !== null && addressNameTags.length > 0) { const oldTags = localStorage.getItem( @@ -156,8 +165,16 @@ export const File = ({ onLoading = () => {} }: Props) => { txPrivateNotes: notes ? JSON.parse(notes) : null, addressNameTags: tags ? JSON.parse(tags) : null, }; + const dataStr = JSON.stringify(data); + const key = new MD5().update(dataStr).digest('hex'); + + const file = { + data, + key, + }; + const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( - JSON.stringify(data), + JSON.stringify(file), )}`; const link = document.createElement('a'); diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index c5fe571db..270b56110 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -41,7 +41,8 @@ }, "file": { "error": { - "invalid": "Invalid file" + "invalid": "Invalid file", + "fileChanged": "The file has been changed, please upload the unchanged file" }, "export": { "button": "Export", diff --git a/src/locales/zh_cn/translation.json b/src/locales/zh_cn/translation.json index 82e40a1c4..a196ba9a5 100644 --- a/src/locales/zh_cn/translation.json +++ b/src/locales/zh_cn/translation.json @@ -40,7 +40,8 @@ }, "file": { "error": { - "invalid": "无效文件" + "invalid": "无效文件", + "fileChanged": "文件已更改,请上传未更改文件" }, "export": { "button": "导出", From 0e6ac22a284093163462c3675638dac7f38ba84a Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Wed, 13 Jul 2022 17:08:00 +0800 Subject: [PATCH 06/23] feat: SCAN-4238 --- src/app/containers/ContractDeployment/ContractInfo.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/containers/ContractDeployment/ContractInfo.tsx b/src/app/containers/ContractDeployment/ContractInfo.tsx index 9a93ecec4..e18c06e66 100644 --- a/src/app/containers/ContractDeployment/ContractInfo.tsx +++ b/src/app/containers/ContractDeployment/ContractInfo.tsx @@ -77,7 +77,8 @@ export const ContractInfo = ({ onChange }) => { const handleFileChange = file => { try { let data = JSON.parse(file); - let bytecode = data.bytecode || data.data?.bytecode?.object; + let bytecode = + data.bytecode?.object || data.bytecode || data.data?.bytecode?.object; if (checkBytecode(bytecode)) { setBytecode(addOx(bytecode)); From 9bb906b97921fb8fe08cffe38f6d278e5265c208 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Thu, 14 Jul 2022 14:59:02 +0800 Subject: [PATCH 07/23] feat: SCAN-4242 --- src/app/containers/Profile/File.tsx | 25 ++++++++++++++++++++----- src/locales/en/translation.json | 3 ++- src/locales/zh_cn/translation.json | 3 ++- src/utils/constants.ts | 4 ++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/app/containers/Profile/File.tsx b/src/app/containers/Profile/File.tsx index 4a4def788..00a3ce905 100644 --- a/src/app/containers/Profile/File.tsx +++ b/src/app/containers/Profile/File.tsx @@ -1,6 +1,6 @@ import React, { createRef } from 'react'; import { FileUpload } from 'app/components/FileUpload'; -import { LOCALSTORAGE_KEYS_MAP } from 'utils/constants'; +import { LOCALSTORAGE_KEYS_MAP, NETWORK_ID } from 'utils/constants'; import { useGlobalData } from 'utils/hooks/useGlobal'; import lodash from 'lodash'; import { InfoIconWithTooltip } from 'app/components/InfoIconWithTooltip/Loadable'; @@ -28,13 +28,26 @@ export const File = ({ onLoading = () => {} }: Props) => { const { data, key } = JSON.parse(file); - if (new MD5().update(JSON.stringify(data)).digest('hex') !== key) { + if ( + new MD5().update(NETWORK_ID + JSON.stringify(data)).digest('hex') !== + key + ) { message.error(t(translations.profile.file.error.fileChanged)); onLoading(false); return; } - const { txPrivateNotes, addressNameTags } = data; + const { chainId, txPrivateNotes, addressNameTags } = data; + + if (chainId && chainId !== NETWORK_ID) { + message.error( + t(translations.profile.file.error.chainIdError, { + chainId: NETWORK_ID, + }), + ); + onLoading(false); + return; + } if (addressNameTags !== null && addressNameTags.length > 0) { const oldTags = localStorage.getItem( @@ -164,8 +177,10 @@ export const File = ({ onLoading = () => {} }: Props) => { const data = { txPrivateNotes: notes ? JSON.parse(notes) : null, addressNameTags: tags ? JSON.parse(tags) : null, + chainId: NETWORK_ID, + version: '1.0.0', }; - const dataStr = JSON.stringify(data); + const dataStr = NETWORK_ID + JSON.stringify(data); const key = new MD5().update(dataStr).digest('hex'); const file = { @@ -179,7 +194,7 @@ export const File = ({ onLoading = () => {} }: Props) => { const link = document.createElement('a'); link.href = jsonString; - link.download = 'confluxscan-user-profile.json'; + link.download = `confluxscan-${NETWORK_ID}-user-profile.json`; link.click(); } catch (e) { message.error(t(translations.profile.file.export.failed)); diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 270b56110..39286ba2d 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -42,7 +42,8 @@ "file": { "error": { "invalid": "Invalid file", - "fileChanged": "The file has been changed, please upload the unchanged file" + "fileChanged": "Invalid file, the file has been changed, please upload the unchanged file", + "chainIdError": "Invaild file, Chaid ID is incorrect, please use file with Chaid ID is {{chainId}}" }, "export": { "button": "Export", diff --git a/src/locales/zh_cn/translation.json b/src/locales/zh_cn/translation.json index a196ba9a5..24de83137 100644 --- a/src/locales/zh_cn/translation.json +++ b/src/locales/zh_cn/translation.json @@ -41,7 +41,8 @@ "file": { "error": { "invalid": "无效文件", - "fileChanged": "文件已更改,请上传未更改文件" + "fileChanged": "无效文件,文件已更改,请上传未更改文件", + "chainIdError": "无效文件,Chain ID 错误,更使用 Chain ID 是 {{chainId}} 的导出文件" }, "export": { "button": "导出", diff --git a/src/utils/constants.ts b/src/utils/constants.ts index aa30e3ffa..461571c0c 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -53,8 +53,8 @@ export enum LOCALSTORAGE_KEYS_MAP { cookieAgreed = 'CONFLUXSCAN_COOKIE_AGREED', txnRecords = 'CONFLUXSCAN_TXN_RECORDS', fccfxNotice = 'CONFLUX_SCAN_FCCFX_NOTICE', - addressLabel = 'CONFLUX_SCAN_ADDRESS_LABEL', - txPrivateNote = 'CONFLUX_SCAN_TX_PRIVATE_NOTE', + addressLabel = 'CONFLUX_SCAN_ADDRESS_LABELS', + txPrivateNote = 'CONFLUX_SCAN_TX_PRIVATE_NOTES', } export const NETWORK_ID = (() => { From 556f27e5ab79ba57145c923c7a6944b0e4a325dd Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Thu, 14 Jul 2022 15:23:00 +0800 Subject: [PATCH 08/23] fix: fixed profile md5 issue --- src/app/containers/Profile/File.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/app/containers/Profile/File.tsx b/src/app/containers/Profile/File.tsx index 00a3ce905..3204e4708 100644 --- a/src/app/containers/Profile/File.tsx +++ b/src/app/containers/Profile/File.tsx @@ -28,10 +28,7 @@ export const File = ({ onLoading = () => {} }: Props) => { const { data, key } = JSON.parse(file); - if ( - new MD5().update(NETWORK_ID + JSON.stringify(data)).digest('hex') !== - key - ) { + if (new MD5().update(JSON.stringify(data)).digest('hex') !== key) { message.error(t(translations.profile.file.error.fileChanged)); onLoading(false); return; @@ -180,7 +177,7 @@ export const File = ({ onLoading = () => {} }: Props) => { chainId: NETWORK_ID, version: '1.0.0', }; - const dataStr = NETWORK_ID + JSON.stringify(data); + const dataStr = JSON.stringify(data); const key = new MD5().update(dataStr).digest('hex'); const file = { From 688e8a29cb9c6642649b13bfbc7d614f4848a5e6 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Mon, 11 Jul 2022 16:23:20 +0800 Subject: [PATCH 09/23] feat: add daily reward detail chart of pos --- .../containers/Charts/pos/DailyRewardInfo.tsx | 110 ++++++++++++++++++ src/app/containers/Charts/pos/Loadable.tsx | 5 + src/app/containers/Charts/pos/index.tsx | 4 + src/app/index.tsx | 7 ++ src/locales/en/translation.json | 11 ++ src/locales/zh_cn/translation.json | 11 ++ src/utils/constants.ts | 1 + 7 files changed, 149 insertions(+) create mode 100644 src/app/containers/Charts/pos/DailyRewardInfo.tsx diff --git a/src/app/containers/Charts/pos/DailyRewardInfo.tsx b/src/app/containers/Charts/pos/DailyRewardInfo.tsx new file mode 100644 index 000000000..f443f1a67 --- /dev/null +++ b/src/app/containers/Charts/pos/DailyRewardInfo.tsx @@ -0,0 +1,110 @@ +import React from 'react'; +import dayjs from 'dayjs'; +import { useTranslation } from 'react-i18next'; +import { translations } from 'locales/i18n'; +import { + StockChartTemplate, + ChildProps, +} from 'app/components/Charts/StockChartTemplate'; +import { OPEN_API_URLS } from 'utils/constants'; +import { Wrapper } from './Wrapper'; +import BigNumber from 'bignumber.js'; + +export function DailyRewardInfo({ preview = false }: ChildProps) { + const { t } = useTranslation(); + + const props = { + preview: preview, + name: 'daily-reward-info', + title: t(translations.highcharts.pos.dailyRewardInfo.title), + subtitle: t(translations.highcharts.pos.dailyRewardInfo.subtitle), + request: { + url: OPEN_API_URLS.PoSDailyRewardInfo, + formatter: data => { + const data1: any = []; + const data2: any = []; + const data3: any = []; + + // TODO, data order issue, need to change by open api + data?.list.reverse().map((d, i) => { + const t = dayjs.utc(d.statDay).valueOf(); + data1.push([ + t, + Number(new BigNumber(d.totalReward).div(1e18).toFixed(2)), + ]); + data2.push([ + t, + Number(new BigNumber(d.avgReward).div(1e18).toFixed(2)), + ]); + data3.push([t, Number(d.rewardAccounts)]); + }); + + return [data1, data2, data3]; + }, + }, + options: { + chart: { + zoomType: 'x', + }, + title: { + text: t(translations.highcharts.pos.dailyRewardInfo.title), + }, + subtitle: { + text: t(translations.highcharts.subtitle), + }, + xAxis: { + type: 'datetime', + }, + yAxis: [ + { + title: { + text: t(translations.highcharts.pos.dailyRewardInfo.yAxisTitle), + }, + height: '50%', + opposite: false, + }, + { + title: { + text: t(translations.highcharts.pos.dailyRewardInfo.yAxisTitle3), + }, + height: '50%', + top: '50%', + offset: 0, + opposite: false, + }, + ], + series: [ + { + type: 'line', + name: `${t( + translations.highcharts.pos.dailyRewardInfo.seriesName, + )}`, + }, + { + type: 'line', + name: `${t( + translations.highcharts.pos.dailyRewardInfo.seriesName2, + )}`, + }, + { + type: 'column', + name: `${t( + translations.highcharts.pos.dailyRewardInfo.seriesName3, + )}`, + color: '#7cb5ec', + yAxis: 1, + // tooltip: { + // // valueDecimals: 2, + // // valueSuffix: ' CFX', + // }, + }, + ], + }, + }; + + return ( + + + + ); +} diff --git a/src/app/containers/Charts/pos/Loadable.tsx b/src/app/containers/Charts/pos/Loadable.tsx index 4e66bc533..8de9a3e48 100644 --- a/src/app/containers/Charts/pos/Loadable.tsx +++ b/src/app/containers/Charts/pos/Loadable.tsx @@ -44,3 +44,8 @@ export const DailyParticipation = lazyLoad( () => import('./DailyParticipation'), module => module.DailyParticipation, ); + +export const DailyRewardInfo = lazyLoad( + () => import('./DailyRewardInfo'), + module => module.DailyRewardInfo, +); diff --git a/src/app/containers/Charts/pos/index.tsx b/src/app/containers/Charts/pos/index.tsx index 42be19122..cbfbf0fd8 100644 --- a/src/app/containers/Charts/pos/index.tsx +++ b/src/app/containers/Charts/pos/index.tsx @@ -13,6 +13,7 @@ import { TotalReward } from './TotalReward'; import { DailyRewardRank } from './DailyRewardRank'; import { DailyDeposit } from './DailyDeposit'; import { DailyParticipation } from './DailyParticipation'; +import { DailyRewardInfo } from './DailyRewardInfo'; export function Chart() { const { t } = useTranslation(); @@ -48,6 +49,9 @@ export function Chart() { + + + diff --git a/src/app/index.tsx b/src/app/index.tsx index f424179eb..00b81bde5 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -103,6 +103,7 @@ import { DailyRewardRank as PoSDailyRewardRank, DailyDeposit as PoSDailyDeposit, DailyParticipation as PoSDailyParticipation, + DailyRewardInfo as PoSDailyRewardInfo, } from './containers/Charts/pos/Loadable'; import { @@ -778,6 +779,12 @@ export function App() { component={PoSDailyRewardRank} /> + + Date: Mon, 11 Jul 2022 17:57:44 +0800 Subject: [PATCH 10/23] feat: add daily cfx transfer count chart of cross space --- ...Contract.tsx => DailyCFXTransferCount.tsx} | 47 ++++++++++++------- .../containers/Charts/crossSpace/Loadable.tsx | 6 +-- .../containers/Charts/crossSpace/index.tsx | 9 ++-- src/app/index.tsx | 6 +-- src/locales/en/translation.json | 5 +- src/locales/zh_cn/translation.json | 7 +-- 6 files changed, 46 insertions(+), 34 deletions(-) rename src/app/containers/Charts/crossSpace/{Contract.tsx => DailyCFXTransferCount.tsx} (51%) diff --git a/src/app/containers/Charts/crossSpace/Contract.tsx b/src/app/containers/Charts/crossSpace/DailyCFXTransferCount.tsx similarity index 51% rename from src/app/containers/Charts/crossSpace/Contract.tsx rename to src/app/containers/Charts/crossSpace/DailyCFXTransferCount.tsx index 627df638f..a673b6217 100644 --- a/src/app/containers/Charts/crossSpace/Contract.tsx +++ b/src/app/containers/Charts/crossSpace/DailyCFXTransferCount.tsx @@ -8,30 +8,34 @@ import { } from 'app/components/Charts/StockChartTemplate'; import { OPEN_API_URLS } from 'utils/constants'; import { Wrapper } from './Wrapper'; -import { CROSS_SPACE_ADDRESS } from 'utils/constants'; +import BigNumber from 'bignumber.js'; -export function Contract({ preview = false }: ChildProps) { +export function DailyCFXTransferCount({ preview = false }: ChildProps) { const { t } = useTranslation(); const props = { preview: preview, - name: 'contract', - title: t(translations.highcharts.crossSpace.contract.title), - subtitle: t(translations.highcharts.crossSpace.contract.subtitle), + name: 'daily-cfx-transfer-count', + title: t(translations.highcharts.crossSpace.dailyCFXTransferCount.title), + subtitle: t( + translations.highcharts.crossSpace.dailyCFXTransferCount.subtitle, + ), request: { - url: OPEN_API_URLS.contract, - query: { - address: CROSS_SPACE_ADDRESS, - limit: 10000, - }, + url: OPEN_API_URLS.CrossSpaceDailyCFXTransfer, formatter: data => { const data1: any = []; const data2: any = []; data?.list?.map((d, i) => { - const t = dayjs.utc(d.statTime).valueOf(); - data1.push([t, Number(d.tx)]); - data2.push([t, Number(d.cfxTransfer)]); + const t = dayjs.utc(d.day).valueOf(); + data1.push([ + t, + Number(new BigNumber(d.DailyCfxCountToEVM).toFixed(2)), + ]); + data2.push([ + t, + Number(new BigNumber(d.DailyCfxCountFromEVM).toFixed(2)), + ]); }); return [data1, data2]; @@ -40,10 +44,9 @@ export function Contract({ preview = false }: ChildProps) { options: { chart: { zoomType: 'x', - type: 'line', }, title: { - text: t(translations.highcharts.crossSpace.contract.title), + text: t(translations.highcharts.crossSpace.dailyCFXTransferCount.title), }, subtitle: { text: t(translations.highcharts.subtitle), @@ -53,18 +56,26 @@ export function Contract({ preview = false }: ChildProps) { }, yAxis: { title: { - text: t(translations.highcharts.crossSpace.contract.yAxisTitle), + text: t( + translations.highcharts.crossSpace.dailyCFXTransferCount.yAxisTitle, + ), }, }, + tooltip: { + shared: true, + }, series: [ { + type: 'line', name: `${t( - translations.highcharts.crossSpace.contract.seriesName, + translations.highcharts.crossSpace.dailyCFXTransferCount.seriesName, )}`, }, { + type: 'line', name: `${t( - translations.highcharts.crossSpace.contract.seriesName2, + translations.highcharts.crossSpace.dailyCFXTransferCount + .seriesName2, )}`, }, ], diff --git a/src/app/containers/Charts/crossSpace/Loadable.tsx b/src/app/containers/Charts/crossSpace/Loadable.tsx index 487fe3635..67af806c5 100644 --- a/src/app/containers/Charts/crossSpace/Loadable.tsx +++ b/src/app/containers/Charts/crossSpace/Loadable.tsx @@ -10,7 +10,7 @@ export const DailyCFXTransfer = lazyLoad( module => module.DailyCFXTransfer, ); -export const Contract = lazyLoad( - () => import('./Contract'), - module => module.Contract, +export const DailyCFXTransferCount = lazyLoad( + () => import('./DailyCFXTransferCount'), + module => module.DailyCFXTransferCount, ); diff --git a/src/app/containers/Charts/crossSpace/index.tsx b/src/app/containers/Charts/crossSpace/index.tsx index abdd7ac30..4abdddcae 100644 --- a/src/app/containers/Charts/crossSpace/index.tsx +++ b/src/app/containers/Charts/crossSpace/index.tsx @@ -6,8 +6,7 @@ import { translations } from 'locales/i18n'; import { StyledChartPreviewWrapper } from '../common/StyledChartPreviewWrapper'; import { DailyCFXTransfer } from './DailyCFXTransfer'; -// TODO disable for temporary, wait for api update -// import { Contract } from './Contract'; +import { DailyCFXTransferCount } from './DailyCFXTransferCount'; export function Chart() { const { t } = useTranslation(); @@ -33,9 +32,9 @@ export function Chart() { - {/* - - */} + + + ); diff --git a/src/app/index.tsx b/src/app/index.tsx index 00b81bde5..3b557f484 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -109,7 +109,7 @@ import { import { Chart as CrossSpaceChart, DailyCFXTransfer as CrossSpaceDailyCFXTransfer, - Contract as CrossSpaceContract, + DailyCFXTransferCount as CrossSpaceDailyCFXTransferCount, } from './containers/Charts/crossSpace/Loadable'; // pos pages @@ -733,8 +733,8 @@ export function App() { Date: Thu, 14 Jul 2022 17:59:13 +0800 Subject: [PATCH 11/23] feat: add pos income rank detail list --- .../pos/IncomingRank/IncomingRankList.tsx | 26 ++++++++++ .../pos/IncomingRank/Leaderboard.tsx | 34 ++++++++++++++ .../containers/pos/IncomingRank/Loadable.tsx | 4 +- src/app/containers/pos/IncomingRank/index.tsx | 47 +++++++------------ src/locales/en/translation.json | 10 +++- src/locales/zh_cn/translation.json | 10 +++- src/utils/tableColumns/pos/incomingRank.tsx | 45 +++++++++++++++++- 7 files changed, 142 insertions(+), 34 deletions(-) create mode 100644 src/app/containers/pos/IncomingRank/IncomingRankList.tsx create mode 100644 src/app/containers/pos/IncomingRank/Leaderboard.tsx diff --git a/src/app/containers/pos/IncomingRank/IncomingRankList.tsx b/src/app/containers/pos/IncomingRank/IncomingRankList.tsx new file mode 100644 index 000000000..fd673ed2e --- /dev/null +++ b/src/app/containers/pos/IncomingRank/IncomingRankList.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { colunms, incomingRankColunms } from 'utils/tableColumns/pos'; +import { utils } from 'utils/tableColumns'; +import { TablePanel as TablePanelNew } from 'app/components/TablePanelNew'; + +export const IncomingRankList = () => { + const url = '/stat/top-pos-account-by-reward'; + const columnsWidth = [0.5, 3, 2]; + const columns = [ + utils.number, + colunms.posAddress, + incomingRankColunms.totalIncoming, + ].map((item, i) => ({ + ...item, + width: columnsWidth[i], + })); + + return ( + + ); +}; diff --git a/src/app/containers/pos/IncomingRank/Leaderboard.tsx b/src/app/containers/pos/IncomingRank/Leaderboard.tsx new file mode 100644 index 000000000..25a4a3f0e --- /dev/null +++ b/src/app/containers/pos/IncomingRank/Leaderboard.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { colunms, incomingRankColunms } from 'utils/tableColumns/pos'; +import { utils } from 'utils/tableColumns'; +import { TablePanel as TablePanelNew } from 'app/components/TablePanelNew'; + +export const Leaderboard = () => { + const url = '/stat/pos-reward-rank?rankField=all'; + + const columnsWidth = [0.5, 1, 1, 1, 1, 1, 1]; + const columns = [ + utils.number, + { + ...colunms.posAddress, + dataIndex: ['accountInfo', 'hex'], + }, + incomingRankColunms.day(1), + incomingRankColunms.day(7), + incomingRankColunms.day(14), + incomingRankColunms.day(30), + incomingRankColunms.day('all'), + ].map((item, i) => ({ + ...item, + width: columnsWidth[i], + })); + + return ( + + ); +}; diff --git a/src/app/containers/pos/IncomingRank/Loadable.tsx b/src/app/containers/pos/IncomingRank/Loadable.tsx index fe0cbf2ac..b27c90d05 100644 --- a/src/app/containers/pos/IncomingRank/Loadable.tsx +++ b/src/app/containers/pos/IncomingRank/Loadable.tsx @@ -10,6 +10,6 @@ export const IncomingRank = lazyLoad( ); export const IncomingRankList = lazyLoad( - () => import('./index'), - module => module.List, + () => import('./IncomingRankList'), + module => module.IncomingRankList, ); diff --git a/src/app/containers/pos/IncomingRank/index.tsx b/src/app/containers/pos/IncomingRank/index.tsx index 807682a24..864436e13 100644 --- a/src/app/containers/pos/IncomingRank/index.tsx +++ b/src/app/containers/pos/IncomingRank/index.tsx @@ -2,36 +2,27 @@ import React from 'react'; import { Helmet } from 'react-helmet-async'; import { useTranslation } from 'react-i18next'; import { translations } from 'locales/i18n'; -import { colunms, incomingRankColunms } from 'utils/tableColumns/pos'; -import { utils } from 'utils/tableColumns'; import { PageHeader } from 'app/components/PageHeader/Loadable'; -import { TablePanel as TablePanelNew } from 'app/components/TablePanelNew'; - -export const List = () => { - const url = '/stat/top-pos-account-by-reward'; - const columnsWidth = [0.5, 3, 2]; - const columns = [ - utils.number, - colunms.posAddress, - incomingRankColunms.totalIncoming, - ].map((item, i) => ({ - ...item, - width: columnsWidth[i], - })); - - return ( - - ); -}; +import { Leaderboard } from './Leaderboard'; +import { TabsTablePanel } from 'app/components/TabsTablePanel/Loadable'; +import { IncomingRankList } from './IncomingRankList'; export function IncomingRank() { const { t } = useTranslation(); + const tabs = [ + { + value: 'top-100', + label: t(translations.pos.incomingRank.top100), + content: , + }, + { + value: 'more', + label: t(translations.pos.incomingRank.last30days), + content: , + }, + ]; + return ( <> @@ -41,10 +32,8 @@ export function IncomingRank() { content={'PoS ' + t(translations.pos.incomingRank.description)} /> - - {t(translations.pos.incomingRank.title)} - - + {t(translations.pos.incomingRank.title)} + ); } diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 90a6cc6cb..82e797bdf 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -2091,7 +2091,15 @@ "title": "Incoming Rank", "description": "Incoming Rank", "subTitle": "Top 100 PoS address by total incoming", - "totalIncoming": "Total Incoming" + "totalIncoming": "Total Incoming", + "top100": "Top 100", + "last30days": "More", + "rewardRank": { + "id": "Account ID", + "day": "{{number}} Day", + "day_plural": "{{number}} Days", + "all": "Overall Income" + } } } } diff --git a/src/locales/zh_cn/translation.json b/src/locales/zh_cn/translation.json index 603655e80..03ac4dc8f 100644 --- a/src/locales/zh_cn/translation.json +++ b/src/locales/zh_cn/translation.json @@ -2088,7 +2088,15 @@ "title": "收益排行", "description": "收益排行", "subTitle": "总收益排行前 100 的 PoS 地址", - "totalIncoming": "总收益" + "totalIncoming": "总收益", + "top100": "前 100 名", + "last30days": "更多", + "rewardRank": { + "id": "账户 ID", + "day": "{{number}} 天", + "day_plural": "{{number}} 天", + "all": "总收入" + } } } } diff --git a/src/utils/tableColumns/pos/incomingRank.tsx b/src/utils/tableColumns/pos/incomingRank.tsx index cdf35519d..3c50cdab5 100644 --- a/src/utils/tableColumns/pos/incomingRank.tsx +++ b/src/utils/tableColumns/pos/incomingRank.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Translation } from 'react-i18next'; +import { Translation, Trans } from 'react-i18next'; import { translations } from 'locales/i18n'; import { ContentWrapper } from '../utils'; import lodash from 'lodash'; @@ -31,3 +31,46 @@ export const totalIncoming = { ); }, }; + +export const accountId = { + title: ( + + + {t => t(translations.pos.incomingRank.rewardRank.id)} + + + ), + dataIndex: 'accountId', + key: 'accountId', + width: 1, + render: value => { + return {value}; + }, +}; + +export const day = (number: number | 'all') => { + return { + title: ( + + {number === 'all' ? ( + + {t => t(translations.pos.incomingRank.rewardRank.all)} + + ) : ( + + {{ number }} Day + + )} + + ), + dataIndex: 'accountId', + key: 'accountId', + width: 1, + render: (_, row) => { + const cfx = fromDripToCfx( + number === 'all' ? row.accountInfo?.totalReward : row[`day${number}`], + ); // new BigNumber(row[`day${number}`]).div(1e18).toFixed(2); + return {cfx}; + }, + }; +}; From 0c7ed0b9a2c24a75cdb86d4c226e643efc809c78 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Fri, 15 Jul 2022 10:16:22 +0800 Subject: [PATCH 12/23] feat: add pagination and sort to pos income rank more list --- src/app/components/TablePanelNew/index.tsx | 7 +-- .../pos/IncomingRank/Leaderboard.tsx | 43 ++++++++++++++----- src/utils/tableColumns/pos/incomingRank.tsx | 7 +-- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/app/components/TablePanelNew/index.tsx b/src/app/components/TablePanelNew/index.tsx index 57da6424d..cc3825e4b 100644 --- a/src/app/components/TablePanelNew/index.tsx +++ b/src/app/components/TablePanelNew/index.tsx @@ -148,13 +148,14 @@ export const TablePanel = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [outerUrl, search]); - const handleTableChange = (pagination, filters, sorter) => { - const { current, pageSize } = pagination; + const handleTableChange = (pagination, _, sorter, extra) => { + const { current = 1, pageSize = 10 } = pagination; const { skip, limit, ...others } = qs.parse(search); + const { action } = extra; let query: Query = { ...others, - skip: String((current - 1) * pageSize) || '0', + skip: action === 'sort' ? '0' : String((current - 1) * pageSize) || '0', limit: pageSize || '10', }; diff --git a/src/app/containers/pos/IncomingRank/Leaderboard.tsx b/src/app/containers/pos/IncomingRank/Leaderboard.tsx index 25a4a3f0e..e79c12ff5 100644 --- a/src/app/containers/pos/IncomingRank/Leaderboard.tsx +++ b/src/app/containers/pos/IncomingRank/Leaderboard.tsx @@ -3,6 +3,12 @@ import { colunms, incomingRankColunms } from 'utils/tableColumns/pos'; import { utils } from 'utils/tableColumns'; import { TablePanel as TablePanelNew } from 'app/components/TablePanelNew'; +const sortConfig = { + sortDirections: ['descend', 'ascend', 'descend'] as Array< + 'descend' | 'ascend' + >, +}; + export const Leaderboard = () => { const url = '/stat/pos-reward-rank?rankField=all'; @@ -13,22 +19,37 @@ export const Leaderboard = () => { ...colunms.posAddress, dataIndex: ['accountInfo', 'hex'], }, - incomingRankColunms.day(1), - incomingRankColunms.day(7), - incomingRankColunms.day(14), - incomingRankColunms.day(30), - incomingRankColunms.day('all'), + { + ...incomingRankColunms.day(1), + sorter: true, + ...sortConfig, + }, + { + ...incomingRankColunms.day(7), + sorter: true, + ...sortConfig, + }, + { + ...incomingRankColunms.day(14), + sorter: true, + ...sortConfig, + }, + { + ...incomingRankColunms.day(30), + sorter: true, + ...sortConfig, + }, + { + ...incomingRankColunms.day('all'), + sorter: true, + ...sortConfig, + }, ].map((item, i) => ({ ...item, width: columnsWidth[i], })); return ( - + ); }; diff --git a/src/utils/tableColumns/pos/incomingRank.tsx b/src/utils/tableColumns/pos/incomingRank.tsx index 3c50cdab5..ce2cbc6f4 100644 --- a/src/utils/tableColumns/pos/incomingRank.tsx +++ b/src/utils/tableColumns/pos/incomingRank.tsx @@ -49,6 +49,7 @@ export const accountId = { }; export const day = (number: number | 'all') => { + const dataIndex = number === 'all' ? 'all' : `day${number}`; return { title: ( @@ -63,13 +64,13 @@ export const day = (number: number | 'all') => { )} ), - dataIndex: 'accountId', - key: 'accountId', + dataIndex: dataIndex, + key: dataIndex, width: 1, render: (_, row) => { const cfx = fromDripToCfx( number === 'all' ? row.accountInfo?.totalReward : row[`day${number}`], - ); // new BigNumber(row[`day${number}`]).div(1e18).toFixed(2); + ); return {cfx}; }, }; From b6a5b0873f579efda62b0ad5e30f7ff47b9c33f2 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Fri, 15 Jul 2022 10:40:15 +0800 Subject: [PATCH 13/23] feat: add default sort key to pos income rank list --- src/app/containers/pos/IncomingRank/Leaderboard.tsx | 3 ++- src/setupProxy.js | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/app/containers/pos/IncomingRank/Leaderboard.tsx b/src/app/containers/pos/IncomingRank/Leaderboard.tsx index e79c12ff5..147a26c4a 100644 --- a/src/app/containers/pos/IncomingRank/Leaderboard.tsx +++ b/src/app/containers/pos/IncomingRank/Leaderboard.tsx @@ -10,7 +10,7 @@ const sortConfig = { }; export const Leaderboard = () => { - const url = '/stat/pos-reward-rank?rankField=all'; + const url = '/stat/pos-reward-rank?rankField=all&reverse=true&orderBy=all'; const columnsWidth = [0.5, 1, 1, 1, 1, 1, 1]; const columns = [ @@ -41,6 +41,7 @@ export const Leaderboard = () => { }, { ...incomingRankColunms.day('all'), + defaultSortOrder: 'descend' as 'descend', sorter: true, ...sortConfig, }, diff --git a/src/setupProxy.js b/src/setupProxy.js index 393e0500f..91b831b46 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -3,8 +3,8 @@ const { createProxyMiddleware } = require('http-proxy-middleware'); // cra doc https://create-react-app.dev/docs/proxying-api-requests-in-development/#configuring-the-proxy-manually // http-proxy-middleware doc https://www.npmjs.com/package/http-proxy-middleware#example -// const url = 'https://www-stage.confluxscan.net'; -const url = 'https://confluxscan.net/'; +const url = 'https://www-stage.confluxscan.net'; +// const url = 'https://confluxscan.net/'; let stat = `${url}`; let v1 = `${url}`; let rpc = `${url}/rpc`; @@ -12,8 +12,8 @@ let rpcv2 = `${url}/rpcv2`; let confluxDag = `${url}`; if (process.env.REACT_APP_TestNet === 'true') { - // const testnet = 'https://testnet-stage.confluxscan.net'; - const testnet = 'https://testnet.confluxscan.net/'; + const testnet = 'https://testnet-stage.confluxscan.net'; + // const testnet = 'https://testnet.confluxscan.net/'; stat = `${testnet}`; v1 = `${testnet}`; rpc = `${testnet}/rpc`; From fa0c9476b8f46e5305293d33a8c3602f704069ff Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Fri, 15 Jul 2022 11:28:41 +0800 Subject: [PATCH 14/23] feat: update style of pos income rank --- .../pos/IncomingRank/Leaderboard.tsx | 2 +- src/utils/tableColumns/pos/incomingRank.tsx | 25 +++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/app/containers/pos/IncomingRank/Leaderboard.tsx b/src/app/containers/pos/IncomingRank/Leaderboard.tsx index 147a26c4a..1ac6f5894 100644 --- a/src/app/containers/pos/IncomingRank/Leaderboard.tsx +++ b/src/app/containers/pos/IncomingRank/Leaderboard.tsx @@ -10,7 +10,7 @@ const sortConfig = { }; export const Leaderboard = () => { - const url = '/stat/pos-reward-rank?rankField=all&reverse=true&orderBy=all'; + const url = '/stat/pos-reward-rank?reverse=true&orderBy=all'; const columnsWidth = [0.5, 1, 1, 1, 1, 1, 1]; const columns = [ diff --git a/src/utils/tableColumns/pos/incomingRank.tsx b/src/utils/tableColumns/pos/incomingRank.tsx index ce2cbc6f4..e883928b6 100644 --- a/src/utils/tableColumns/pos/incomingRank.tsx +++ b/src/utils/tableColumns/pos/incomingRank.tsx @@ -5,6 +5,8 @@ import { ContentWrapper } from '../utils'; import lodash from 'lodash'; import { fromDripToCfx } from 'utils'; import { Text } from 'app/components/Text/Loadable'; +import { PlusOutlined } from '@ant-design/icons'; +import styled from 'styled-components/macro'; export const totalIncoming = { title: ( @@ -52,7 +54,7 @@ export const day = (number: number | 'all') => { const dataIndex = number === 'all' ? 'all' : `day${number}`; return { title: ( - + {number === 'all' ? ( {t => t(translations.pos.incomingRank.rewardRank.all)} @@ -71,7 +73,26 @@ export const day = (number: number | 'all') => { const cfx = fromDripToCfx( number === 'all' ? row.accountInfo?.totalReward : row[`day${number}`], ); - return {cfx}; + + return ( + + + {cfx !== '0' && } + {cfx} + + + ); }, }; }; + +const StyledDayWrapper = styled.div` + display: inline-flex; + align-items: center; + + .icon { + font-size: 10px; + font-weight: bold; + margin-right: 1px; + } +`; From a66507756f0f3a59847bb76cf0d44b9ce6e8a5aa Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Fri, 15 Jul 2022 14:26:31 +0800 Subject: [PATCH 15/23] fix: SCAN-4237 --- .../containers/Profile/CreateAddressLabel.tsx | 19 ++++++------------- src/app/containers/Profile/CreateTxNote.tsx | 19 ++++++------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/app/containers/Profile/CreateAddressLabel.tsx b/src/app/containers/Profile/CreateAddressLabel.tsx index e270a09d7..7af935a2a 100644 --- a/src/app/containers/Profile/CreateAddressLabel.tsx +++ b/src/app/containers/Profile/CreateAddressLabel.tsx @@ -66,6 +66,11 @@ export function CreateAddressLabel({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [outerList]); + useEffect(() => { + form.setFieldsValue(data); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data]); + const handleOk = () => { form.validateFields().then(async function ({ address, label }) { try { @@ -190,11 +195,6 @@ export function CreateAddressLabel({ delete: t(translations.general.delete), }; - const d = { - ...data, - label: list.filter(l => l.a === data.address)[0]?.l, - }; - return ( -
+ { + form.setFieldsValue(data); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data]); + const handleOk = () => { form.validateFields().then(async function ({ hash, note }) { try { @@ -166,11 +171,6 @@ export function CreateTxNote({ delete: t(translations.general.delete), }; - const d = { - ...data, - note: list.filter(l => l.h === data.hash)[0]?.n, - }; - return ( - + Date: Tue, 19 Jul 2022 16:44:32 +0800 Subject: [PATCH 16/23] feat: debug with scan backend api upgrade --- .github/CONTRIBUTING.md | 2 +- README.md | 2 +- src/app/containers/Blocks/Dag/lib-dag.js | 62 ++++++++++++------------ src/app/containers/Footer/index.tsx | 2 +- src/utils/request.ts | 11 ++--- 5 files changed, 38 insertions(+), 41 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3f9940310..19ad12334 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -10,7 +10,7 @@ Hi! We are really excited that you are interested in contributing to Conflux. Be ## Issue Reporting Guidelines -- Please check the existing issues and the [Conflux Bounty Site](https://bounty.conflux-chain.org) to avoid submitting duplicate issues. +- Please check the existing issues and the [Conflux Bounty Site](https://bounty.confluxnetwork.org) to avoid submitting duplicate issues. ## Pull Request Guidelines diff --git a/README.md b/README.md index 3b715855e..f14c581ed 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Source code of [Conflux Scan](https://confluxscan.io) Conflux Scan is still in its early stages compared to [Etherscan](https://etherscan.io). So there's a lot features and improvements waiting there. You can find bugs, request new features, send PRs to improve the code and docs. Don't forget to -check out the [Conflux Bounty](https://bounty.conflux-chain.org) to earn reward +check out the [Conflux Bounty](https://bounty.confluxnetwork.org) to earn reward while improving scan. ## Contributing diff --git a/src/app/containers/Blocks/Dag/lib-dag.js b/src/app/containers/Blocks/Dag/lib-dag.js index ed37027da..401e2af09 100644 --- a/src/app/containers/Blocks/Dag/lib-dag.js +++ b/src/app/containers/Blocks/Dag/lib-dag.js @@ -111,40 +111,42 @@ function subscribe(height, cb) { sendNextRequest = false; fetch('/v1/dag') .then(e => e.json()) - .then(({ list }) => { - const _epochs = list.map(epoch => { - const _epoch = {}; - let [pivot, ...rest] = epoch; - const { epochNumber, ...pivotInfo } = pivot; - //data from server can be wrong - rest = rest.filter(d => d.epochNumber === epochNumber); - _epoch.epochNumber = epochNumber; - _epoch.colors = getEpochColor(epochNumber); - _epoch.points = []; - const { points, width } = layout({ - n: rest.length, - d: 30, - h: height, - }); + .then(({ data, code, message }) => { + if (code === 0) { + const _epochs = data.list.map(epoch => { + const _epoch = {}; + let [pivot, ...rest] = epoch; + const { epochNumber, ...pivotInfo } = pivot; + //data from server can be wrong + rest = rest.filter(d => d.epochNumber === epochNumber); + _epoch.epochNumber = epochNumber; + _epoch.colors = getEpochColor(epochNumber); + _epoch.points = []; + const { points, width } = layout({ + n: rest.length, + d: 30, + h: height, + }); - //pivot - _epoch.points.push({ - offsetX: width, - y: height / 2, - ...pivotInfo, - }); - rest.forEach((block, i) => { - const p = points[i]; + //pivot _epoch.points.push({ - offsetX: p[0], - y: p[1], - ...block, + offsetX: width, + y: height / 2, + ...pivotInfo, + }); + rest.forEach((block, i) => { + const p = points[i]; + _epoch.points.push({ + offsetX: p[0], + y: p[1], + ...block, + }); }); + return _epoch; }); - return _epoch; - }); - sendNextRequest = true; - cb((epochs = concat(_epochs, epochs))); + sendNextRequest = true; + cb((epochs = concat(_epochs, epochs))); + } }) .catch(() => { sendNextRequest = true; diff --git a/src/app/containers/Footer/index.tsx b/src/app/containers/Footer/index.tsx index 8dbc43551..29faed4ef 100644 --- a/src/app/containers/Footer/index.tsx +++ b/src/app/containers/Footer/index.tsx @@ -115,7 +115,7 @@ export function Footer() { const bountyLink = ( > & { abort?: () => void; @@ -77,14 +76,10 @@ const parseJSON = async function (response) { // 检查返回值中是否包含错误 const checkResponse = ({ data, response }) => { - // compatible with open api request - if (response.status === 200 && lodash.isNil(data.code)) { - return data; - } else if (data.code === 0) { - // compatible with /stat backend api - return data.data || data; + if (response.status === 200 && data.code === 0) { + return data.data; } else { - const code = Number(data?.code); + const code = Number(data.code); publishRequestError({ code: code, message: data.message }, 'http'); const error: Partial & { response?: ResponseType; From 26b289c6ee3d1b548dcb6c2b382e195433c5b841 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Tue, 19 Jul 2022 17:39:20 +0800 Subject: [PATCH 17/23] feat: reset backend response refactor compatible --- src/app/containers/Blocks/Dag/lib-dag.js | 62 ++++++++++++------------ src/utils/request.ts | 11 +++-- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/app/containers/Blocks/Dag/lib-dag.js b/src/app/containers/Blocks/Dag/lib-dag.js index 401e2af09..ed37027da 100644 --- a/src/app/containers/Blocks/Dag/lib-dag.js +++ b/src/app/containers/Blocks/Dag/lib-dag.js @@ -111,42 +111,40 @@ function subscribe(height, cb) { sendNextRequest = false; fetch('/v1/dag') .then(e => e.json()) - .then(({ data, code, message }) => { - if (code === 0) { - const _epochs = data.list.map(epoch => { - const _epoch = {}; - let [pivot, ...rest] = epoch; - const { epochNumber, ...pivotInfo } = pivot; - //data from server can be wrong - rest = rest.filter(d => d.epochNumber === epochNumber); - _epoch.epochNumber = epochNumber; - _epoch.colors = getEpochColor(epochNumber); - _epoch.points = []; - const { points, width } = layout({ - n: rest.length, - d: 30, - h: height, - }); + .then(({ list }) => { + const _epochs = list.map(epoch => { + const _epoch = {}; + let [pivot, ...rest] = epoch; + const { epochNumber, ...pivotInfo } = pivot; + //data from server can be wrong + rest = rest.filter(d => d.epochNumber === epochNumber); + _epoch.epochNumber = epochNumber; + _epoch.colors = getEpochColor(epochNumber); + _epoch.points = []; + const { points, width } = layout({ + n: rest.length, + d: 30, + h: height, + }); - //pivot + //pivot + _epoch.points.push({ + offsetX: width, + y: height / 2, + ...pivotInfo, + }); + rest.forEach((block, i) => { + const p = points[i]; _epoch.points.push({ - offsetX: width, - y: height / 2, - ...pivotInfo, - }); - rest.forEach((block, i) => { - const p = points[i]; - _epoch.points.push({ - offsetX: p[0], - y: p[1], - ...block, - }); + offsetX: p[0], + y: p[1], + ...block, }); - return _epoch; }); - sendNextRequest = true; - cb((epochs = concat(_epochs, epochs))); - } + return _epoch; + }); + sendNextRequest = true; + cb((epochs = concat(_epochs, epochs))); }) .catch(() => { sendNextRequest = true; diff --git a/src/utils/request.ts b/src/utils/request.ts index 5c8c07830..2646ccd26 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,6 +1,7 @@ import { PromiseType } from 'react-use/lib/util'; import { appendApiPrefix } from './api'; import { publishRequestError } from './index'; +import lodash from 'lodash'; type FetchWithAbortType = Partial> & { abort?: () => void; @@ -76,10 +77,14 @@ const parseJSON = async function (response) { // 检查返回值中是否包含错误 const checkResponse = ({ data, response }) => { - if (response.status === 200 && data.code === 0) { - return data.data; + // compatible with open api request + if (response.status === 200 && lodash.isNil(data.code)) { + return data; + } else if (data.code === 0) { + // compatible with /stat backend api + return data.data || data; } else { - const code = Number(data.code); + const code = Number(data?.code); publishRequestError({ code: code, message: data.message }, 'http'); const error: Partial & { response?: ResponseType; From 237596c5735e2ee1bed5bfdd70327ab846ee9e0e Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Wed, 20 Jul 2022 10:25:33 +0800 Subject: [PATCH 18/23] feat: update util fn request and dag --- src/app/containers/Blocks/Dag/lib-dag.js | 62 ++++++++++++------------ src/utils/request.ts | 11 ++--- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/app/containers/Blocks/Dag/lib-dag.js b/src/app/containers/Blocks/Dag/lib-dag.js index ed37027da..401e2af09 100644 --- a/src/app/containers/Blocks/Dag/lib-dag.js +++ b/src/app/containers/Blocks/Dag/lib-dag.js @@ -111,40 +111,42 @@ function subscribe(height, cb) { sendNextRequest = false; fetch('/v1/dag') .then(e => e.json()) - .then(({ list }) => { - const _epochs = list.map(epoch => { - const _epoch = {}; - let [pivot, ...rest] = epoch; - const { epochNumber, ...pivotInfo } = pivot; - //data from server can be wrong - rest = rest.filter(d => d.epochNumber === epochNumber); - _epoch.epochNumber = epochNumber; - _epoch.colors = getEpochColor(epochNumber); - _epoch.points = []; - const { points, width } = layout({ - n: rest.length, - d: 30, - h: height, - }); + .then(({ data, code, message }) => { + if (code === 0) { + const _epochs = data.list.map(epoch => { + const _epoch = {}; + let [pivot, ...rest] = epoch; + const { epochNumber, ...pivotInfo } = pivot; + //data from server can be wrong + rest = rest.filter(d => d.epochNumber === epochNumber); + _epoch.epochNumber = epochNumber; + _epoch.colors = getEpochColor(epochNumber); + _epoch.points = []; + const { points, width } = layout({ + n: rest.length, + d: 30, + h: height, + }); - //pivot - _epoch.points.push({ - offsetX: width, - y: height / 2, - ...pivotInfo, - }); - rest.forEach((block, i) => { - const p = points[i]; + //pivot _epoch.points.push({ - offsetX: p[0], - y: p[1], - ...block, + offsetX: width, + y: height / 2, + ...pivotInfo, + }); + rest.forEach((block, i) => { + const p = points[i]; + _epoch.points.push({ + offsetX: p[0], + y: p[1], + ...block, + }); }); + return _epoch; }); - return _epoch; - }); - sendNextRequest = true; - cb((epochs = concat(_epochs, epochs))); + sendNextRequest = true; + cb((epochs = concat(_epochs, epochs))); + } }) .catch(() => { sendNextRequest = true; diff --git a/src/utils/request.ts b/src/utils/request.ts index 2646ccd26..5c8c07830 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,7 +1,6 @@ import { PromiseType } from 'react-use/lib/util'; import { appendApiPrefix } from './api'; import { publishRequestError } from './index'; -import lodash from 'lodash'; type FetchWithAbortType = Partial> & { abort?: () => void; @@ -77,14 +76,10 @@ const parseJSON = async function (response) { // 检查返回值中是否包含错误 const checkResponse = ({ data, response }) => { - // compatible with open api request - if (response.status === 200 && lodash.isNil(data.code)) { - return data; - } else if (data.code === 0) { - // compatible with /stat backend api - return data.data || data; + if (response.status === 200 && data.code === 0) { + return data.data; } else { - const code = Number(data?.code); + const code = Number(data.code); publishRequestError({ code: code, message: data.message }, 'http'); const error: Partial & { response?: ResponseType; From f3a5d671f661dfa3bc17dfdb261b672f01da9e0b Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Thu, 21 Jul 2022 09:47:13 +0800 Subject: [PATCH 19/23] fix: fixed table sort issue --- src/app/components/TablePanelNew/index.tsx | 15 ++++++++++++++- src/locales/zh_cn/translation.json | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/app/components/TablePanelNew/index.tsx b/src/app/components/TablePanelNew/index.tsx index cc3825e4b..3c99e8570 100644 --- a/src/app/components/TablePanelNew/index.tsx +++ b/src/app/components/TablePanelNew/index.tsx @@ -92,6 +92,8 @@ export const TablePanel = ({ error: null, }); + const { orderBy, reverse } = useMemo(() => qs.parse(search), [search]); + const getQuery = useMemo(() => { let defaultPagination = !pagination ? { @@ -175,6 +177,17 @@ export const TablePanel = ({ const total = dataSource && Array.isArray(dataSource) ? dataSource.length : stateTotal; + let _columns: any = columns; + if (orderBy !== undefined) { + _columns = columns?.map(c => { + delete c.defaultSortOrder; + if (c.key === orderBy) { + c.defaultSortOrder = reverse === 'true' ? 'descend' : 'ascend'; + } + return c; + }); + } + return ( Date: Thu, 21 Jul 2022 10:46:35 +0800 Subject: [PATCH 20/23] feat: compatible with scan backend api upgrade --- src/app/containers/BalanceChecker/Result.tsx | 58 +++++++++++-------- src/app/containers/Report/index.tsx | 4 +- .../components/DebounceTokenSelect.tsx | 37 +++++------- 3 files changed, 52 insertions(+), 47 deletions(-) diff --git a/src/app/containers/BalanceChecker/Result.tsx b/src/app/containers/BalanceChecker/Result.tsx index 29ed508be..3c0468bbc 100644 --- a/src/app/containers/BalanceChecker/Result.tsx +++ b/src/app/containers/BalanceChecker/Result.tsx @@ -45,37 +45,47 @@ export function Result({ radioValue, resultVisible, formData }) { }; useEffect(() => { initResult(); - if (data?.code === 501) { - setResultData({ - epoch_dt: '--', - epoch: '--', - balance: 0, - }); - setLoading(false); - } else if (data?.code === 0) { - const { cfxByEpoch, cfxByDt } = data; - if (cfxByEpoch) { - setResultData({ - ...cfxByEpoch, - epoch_dt: formData.dt === '' ? cfxByEpoch.epoch_dt : formData.dt, - }); - } else if (cfxByDt) { - setResultData({ - ...cfxByDt, - // @ts-ignore - epoch_dt: dayjs(formData.dt).isToday() - ? formData.dt - : dayjs(formData.dt).add(1, 'day').toString(), - }); + try { + const { cfxByEpoch, cfxByDt } = data || {}; + if (cfxByEpoch || cfxByDt) { + if (cfxByEpoch) { + setResultData({ + ...cfxByEpoch, + epoch_dt: formData.dt === '' ? cfxByEpoch.epoch_dt : formData.dt, + }); + } else if (cfxByDt) { + setResultData({ + ...cfxByDt, + // @ts-ignore + epoch_dt: dayjs(formData.dt).isToday() + ? formData.dt + : dayjs(formData.dt).add(1, 'day').toString(), + }); + } else { + setResultData({ + epoch_dt: '--', + epoch: '--', + balance: 0, + }); + } + setLoading(false); } else { setResultData({ epoch_dt: '--', epoch: '--', balance: 0, }); - } + setLoading(false); + } // eslint-disable-next-line react-hooks/exhaustive-deps + } catch (e) { + setResultData({ + epoch_dt: '--', + epoch: '--', + balance: 0, + }); setLoading(false); - } // eslint-disable-next-line react-hooks/exhaustive-deps + } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [data]); const TokenQuantityCard = ( diff --git a/src/app/containers/Report/index.tsx b/src/app/containers/Report/index.tsx index 343b07329..8b7cfc293 100644 --- a/src/app/containers/Report/index.tsx +++ b/src/app/containers/Report/index.tsx @@ -34,8 +34,8 @@ export function Report() { const onFinish = (values: any) => { setLoading(true); reqReport(values) - .then(resp => { - if (resp.code !== 0) { + .then(({ report }) => { + if (report !== 'ok') { throw new Error(t(translations.report.status.fail)); } else { setMessage({ diff --git a/src/app/containers/Transactions/components/DebounceTokenSelect.tsx b/src/app/containers/Transactions/components/DebounceTokenSelect.tsx index a51a89b30..ac36e9cf8 100644 --- a/src/app/containers/Transactions/components/DebounceTokenSelect.tsx +++ b/src/app/containers/Transactions/components/DebounceTokenSelect.tsx @@ -43,36 +43,31 @@ export async function getRecommendTokenList( accountAddress: account, transferType: transferType, }, - }).then(resp => { + }).then(data => { let result: Array = []; - try { - if (!resp.code) { - result = resp.list.map(l => ({ - iconUrl: l.iconUrl, - name: l.name, - address: formatAddress(l.address), - })); - } - } catch (e) {} + if (data?.list) { + result = data.list.map(l => ({ + iconUrl: l.iconUrl, + name: l.name, + address: formatAddress(l.address), + })); + } return result; }); } -const formatTokenList = resp => { +const formatTokenList = data => { let result: Array = []; - try { - // no 'code' from response data, use total for temp - if (resp.total) { - result = resp.list.map(l => ({ - iconUrl: l.iconUrl, - name: l.name, - address: formatAddress(l.address), - })); - } - } catch (e) {} + if (data?.total) { + result = data.list.map(l => ({ + iconUrl: l.iconUrl, + name: l.name, + address: formatAddress(l.address), + })); + } return result; }; From 516ec64dafdefdf79d0c0e55e6b48b3b8e5b7691 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Thu, 21 Jul 2022 16:28:24 +0800 Subject: [PATCH 21/23] feat: add faucet to tools --- src/app/containers/Header/index.tsx | 124 +++++++++++++++------------- src/locales/en/translation.json | 1 + src/locales/zh_cn/translation.json | 1 + src/utils/gaConstants.ts | 1 + 4 files changed, 69 insertions(+), 58 deletions(-) diff --git a/src/app/containers/Header/index.tsx b/src/app/containers/Header/index.tsx index f11cdcc1a..554e0d4ac 100644 --- a/src/app/containers/Header/index.tsx +++ b/src/app/containers/Header/index.tsx @@ -134,6 +134,62 @@ export const Header = memo(() => { }, ]; + const toolItems = [ + { + title: [ + t(translations.header.addressConverter), + , + ], + name: ScanEvent.menu.action.addressConverter, + afterClick: menuClick, + href: '/address-converter', + }, + { + title: [ + t(translations.header.broadcastTx), + , + ], + name: ScanEvent.menu.action.broadcastTx, + afterClick: menuClick, + href: '/push-tx', + }, + { + title: [ + t(translations.header.blocknumberCalc), + , + ], + name: ScanEvent.menu.action.blocknumberCalc, + afterClick: menuClick, + href: '/block-countdown', + }, + { + title: [ + t(translations.header.nftChecker), + , + ], + name: ScanEvent.menu.action.nftChecker, + afterClick: menuClick, + href: '/nft-checker', + }, + { + title: [ + t(translations.header.balanceChecker), + , + ], + name: ScanEvent.menu.action.balanceChecker, + afterClick: menuClick, + href: '/balance-checker', + }, + { + // profile + title: [t(translations.header.profile), ], + name: ScanEvent.menu.action.home, + afterClick: menuClick, + href: '/profile', + className: 'profile', + }, + ]; + ecosystemItems.push({ title: [t(translations.header.fcCfx), ], name: ScanEvent.menu.action.fcCfx, @@ -193,6 +249,15 @@ export const Header = memo(() => { }); } + if (NETWORK_TYPE === NETWORK_TYPES.testnet) { + toolItems.unshift({ + title: [t(translations.header.faucet), ], + name: ScanEvent.menu.action.faucet, + afterClick: menuClick, + href: 'https://faucet.confluxnetwork.org/', + }); + } + const startLinks: HeaderLinks = [ { // home @@ -473,64 +538,7 @@ export const Header = memo(() => { ], name: ScanEvent.menu.action.tools, plain: true, - children: [ - { - title: [ - t(translations.header.addressConverter), - , - ], - name: ScanEvent.menu.action.addressConverter, - afterClick: menuClick, - href: '/address-converter', - }, - { - title: [ - t(translations.header.broadcastTx), - , - ], - name: ScanEvent.menu.action.broadcastTx, - afterClick: menuClick, - href: '/push-tx', - }, - { - title: [ - t(translations.header.blocknumberCalc), - , - ], - name: ScanEvent.menu.action.blocknumberCalc, - afterClick: menuClick, - href: '/block-countdown', - }, - { - title: [ - t(translations.header.nftChecker), - , - ], - name: ScanEvent.menu.action.nftChecker, - afterClick: menuClick, - href: '/nft-checker', - }, - { - title: [ - t(translations.header.balanceChecker), - , - ], - name: ScanEvent.menu.action.balanceChecker, - afterClick: menuClick, - href: '/balance-checker', - }, - { - // profile - title: [ - t(translations.header.profile), - , - ], - name: ScanEvent.menu.action.home, - afterClick: menuClick, - href: '/profile', - className: 'profile', - }, - ], + children: toolItems, }, { title: [ diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 82e797bdf..dbbe08168 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -468,6 +468,7 @@ "searchPlaceHolder": "Search by Epoch / Block Hash / Txn Hash / Address / Token / Contract Name Tag", "searchPlaceHolderMobile": "Epoch/Block Hash/Txn Hash/Address/Token/Contract Name Tag", "addressConverter": "Address Format Conversion", + "faucet": "Test Faucet", "broadcastTx": "Broadcast Transaction", "blocknumberCalc": "Blocknumber Calculator", "nftChecker": "NFT Checker", diff --git a/src/locales/zh_cn/translation.json b/src/locales/zh_cn/translation.json index 17b79d55e..236fb491d 100644 --- a/src/locales/zh_cn/translation.json +++ b/src/locales/zh_cn/translation.json @@ -467,6 +467,7 @@ "searchPlaceHolder": "请输入纪元 / 区块哈希 / 交易哈希 / 地址 / 通证 / 合约名称标签", "searchPlaceHolderMobile": "纪元/区块哈希/交易哈希/地址/通证/合约名称标签", "addressConverter": "地址格式转换", + "faucet": "测试水管", "broadcastTx": "广播交易", "blocknumberCalc": "区块计算器", "nftChecker": "数字藏品查看器", diff --git a/src/utils/gaConstants.ts b/src/utils/gaConstants.ts index b4afea787..29b6a3f6a 100644 --- a/src/utils/gaConstants.ts +++ b/src/utils/gaConstants.ts @@ -25,6 +25,7 @@ export const ScanEvent = { fluentWallet: 'portal', confluxBounty: 'bounty', addressConverter: 'address_converter', + faucet: 'faucet', tools: 'tools', balanceChecker: 'balance_checker', more: 'more', From 8ed990a5cf5dccfbaf902491c989a764f6f6161b Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Fri, 22 Jul 2022 18:01:22 +0800 Subject: [PATCH 22/23] feat: upgrade js-conflux-sdk version --- package.json | 4 ++-- src/utils/index.ts | 8 +------- yarn.lock | 25 +++++++++---------------- 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 76d7c71ae..e121e3c42 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "@cfxjs/antd": "1.0.6", "@cfxjs/react-ui": "2.0.0-alpha.15", "@cfxjs/use-wallet": "0.0.18", - "@conflux-dev/conflux-address-js": "1.1.7", + "@conflux-dev/conflux-address-js": "1.3.16", "@testing-library/jest-dom": "5.1.1", "@testing-library/react": "10.0.1", "@types/fontfaceobserver": "0.0.6", @@ -41,7 +41,7 @@ "i18next": "19.3.4", "i18next-browser-languagedetector": "4.0.2", "jest-styled-components": "7.0.2", - "js-conflux-sdk": "2.0.6", + "js-conflux-sdk": "2.1.6", "lint-staged": "10.0.8", "lodash": "4.17.20", "md5.js": "1.3.5", diff --git a/src/utils/index.ts b/src/utils/index.ts index 10424c83b..5c7bda4d8 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -9,7 +9,6 @@ import { NETWORK_ID, NETWORK_TYPE, NETWORK_TYPES, - CFX, } from 'utils/constants'; import SDK from 'js-conflux-sdk/dist/js-conflux-sdk.umd.min.js'; import pubsub from './pubsub'; @@ -144,12 +143,7 @@ export function isContractAddress(address: string): boolean { export function isInnerContractAddress(address: string): boolean { try { - // @todo, wait for sdk upgrade to accept both base32 and hex address - return ( - SDK.address.isInternalContractAddress(formatAddress(address, 'hex')) || - formatAddress(address, 'hex') === - CFX.InternalContract('CrossSpaceCall').address - ); + return SDK.address.isInternalContractAddress(formatAddress(address, 'hex')); } catch (e) { return false; } diff --git a/yarn.lock b/yarn.lock index 2b7c1a66c..9d259b9c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1620,13 +1620,6 @@ dependencies: chalk "^4.0.0" -"@conflux-dev/conflux-address-js@1.1.7": - version "1.1.7" - resolved "https://registry.npmjs.org/@conflux-dev/conflux-address-js/-/conflux-address-js-1.1.7.tgz" - integrity sha512-POY+9UQ2SLWgXZfxG9pf5u9LGS98WXyNv1xsDN1ucUQEk2GKfWBstOc/CnougMzC8n3PEbvdedDoiMSZ3wX1qg== - dependencies: - jsbi "^3.1.4" - "@conflux-dev/conflux-address-js@1.1.8": version "1.1.8" resolved "https://registry.npmjs.org/@conflux-dev/conflux-address-js/-/conflux-address-js-1.1.8.tgz" @@ -1634,10 +1627,10 @@ dependencies: jsbi "^3.1.4" -"@conflux-dev/conflux-address-js@^1.3.10": - version "1.3.10" - resolved "https://registry.npmjs.org/@conflux-dev/conflux-address-js/-/conflux-address-js-1.3.10.tgz" - integrity sha512-B5lM24cJeaZJVCGJ825eZ2FuKOLXMJkkK6ZrC7tciLOGwefOua9egUtqCPD3uojTT/QPS45LOlQHIpfgG+M1yA== +"@conflux-dev/conflux-address-js@1.3.16", "@conflux-dev/conflux-address-js@^1.3.16": + version "1.3.16" + resolved "https://registry.yarnpkg.com/@conflux-dev/conflux-address-js/-/conflux-address-js-1.3.16.tgz#2ae7733138fe160e177392d7e1dc5f27590d1ee6" + integrity sha512-9n7wFCr7Wu4WYdngPfxB63bRHSk+0xWFHVqVwUPddg3oIRT+sQm+TcHGiXaiuvnjnvjDFfCMbHnjZ+a8X5C/aA== dependencies: jsbi "^3.1.4" @@ -9827,12 +9820,12 @@ jest@24.9.0: import-local "^2.0.0" jest-cli "^24.9.0" -js-conflux-sdk@2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/js-conflux-sdk/-/js-conflux-sdk-2.0.6.tgz" - integrity sha512-bCjJelUbr6BuVAF+SzbbXyShI+ckRUSYEsECw/0tcpIybVhpxocAQiN9WgWQYv8JmU4QzwJZ9fp0H2Ok+qk4Ng== +js-conflux-sdk@2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/js-conflux-sdk/-/js-conflux-sdk-2.1.6.tgz#3abb19620aa0d83fa2d77f52698d151e7d7fa226" + integrity sha512-y/j6atNPnEcXiMoKWPaUgWVtbqKVJ8Qp14CXteHUzLHa7I3IytsklYUfNEil0qc3w2794ynQ0f08MPThK8cEFw== dependencies: - "@conflux-dev/conflux-address-js" "^1.3.10" + "@conflux-dev/conflux-address-js" "^1.3.16" abi-util-lite "^0.1.0" big.js "^5.2.2" commander "^8.0.0" From cfa328c3e5b5f635919c4d148ebe16230a36463e Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Tue, 26 Jul 2022 09:36:50 +0800 Subject: [PATCH 23/23] feat: update release note and version --- src/app/containers/Notices/index.tsx | 8 ++++---- src/index.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/containers/Notices/index.tsx b/src/app/containers/Notices/index.tsx index ef6cd2fab..9260a411e 100644 --- a/src/app/containers/Notices/index.tsx +++ b/src/app/containers/Notices/index.tsx @@ -12,14 +12,14 @@ export const noticeInfo = { hot: false, type: 'Announcement', brief: { - en: 'ConfluxScan V2.14.0 Released!', - zh: 'ConfluxScan V2.14.0 发布喽!', + en: 'ConfluxScan v2.15.0 Released!', + zh: 'ConfluxScan v2.15.0 发布喽!', }, link: { en: - 'https://confluxscansupportcenter.zendesk.com/hc/en-us/articles/7059591985819-Jun-10-2022-Jul-4-2022', + 'https://confluxscansupportcenter.zendesk.com/hc/en-us/articles/7607301421339-Jul-5-2022-Jul-24-2022', zh: - 'https://confluxscansupportcenter.zendesk.com/hc/zh-cn/articles/7059591985819-2022-6-10-2022-7-4', + 'https://confluxscansupportcenter.zendesk.com/hc/zh-cn/articles/7607301421339-2022-7-5-2022-7-24', }, }; diff --git a/src/index.tsx b/src/index.tsx index 84fcb84a7..9a34dc77e 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -61,7 +61,7 @@ Promise.all([completeDetect()]).then(() => { render(App); }); -const currentVersion = 'V2.14.0'; +const currentVersion = 'v2.15.0'; const brand = ` ┌─┐┌─┐┌┐┌┌─┐┬ ┬ ┬─┐ ┬ ┌─┐┌─┐┌─┐┌┐┌ ${currentVersion}