From 6c8a9d444966b76956a58253b33963d3ddabfb5b Mon Sep 17 00:00:00 2001 From: Jarryd Allison Date: Thu, 3 Nov 2022 10:30:44 -0600 Subject: [PATCH] Fix multi-sig account view with a nice modal --- .../Accounts/Components/AccountSpotlight.tsx | 54 +++++++++++++----- .../Components/AccountMultiSigModal.tsx | 55 +++++++++++++++++++ .../AccountTables/Components/index.ts | 1 + src/Pages/Tx/Components/TxInformation.js | 11 ++-- src/redux/features/account/accountSlice.ts | 18 ++++-- src/redux/features/tx/txSlice.ts | 13 ++--- src/utils/table/formatTableData.js | 10 +--- 7 files changed, 123 insertions(+), 39 deletions(-) create mode 100644 src/Pages/Accounts/Components/AccountTables/Components/AccountMultiSigModal.tsx diff --git a/src/Pages/Accounts/Components/AccountSpotlight.tsx b/src/Pages/Accounts/Components/AccountSpotlight.tsx index cf0512f5..c083e88d 100644 --- a/src/Pages/Accounts/Components/AccountSpotlight.tsx +++ b/src/Pages/Accounts/Components/AccountSpotlight.tsx @@ -1,10 +1,17 @@ import { useEffect, useState } from 'react'; import styled from 'styled-components'; +// @ts-ignore +import useToggle from 'react-tiny-hooks/use-toggle'; import { Link, useParams } from 'react-router-dom'; import { useAccounts } from 'redux/hooks'; -import { DataCard, CopyValue } from 'Components'; +import { DataCard, CopyValue, Button as BaseButton } from 'Components'; import { PopupDataProps } from 'Components/Summary/Summary'; import { maxLength, formatDenom } from 'utils'; +import { AccountMultiSigModal } from './AccountTables/Components'; + +const Button = styled(BaseButton)` + margin: 0; +`; const Group = styled.div` display: flex; @@ -12,7 +19,7 @@ const Group = styled.div` export const AccountSpotlight = () => { const { accountInfo, getAccountAssets, getAccountInfo, getAccountRewards } = useAccounts(); - + const [modalOpen, deactivateModalOpen, activateModalOpen] = useToggle(false); const { addressId } = useParams<{ addressId: string }>(); const [showKeyPopup, setShowKeyPopup] = useState(false); const [showAUMPopup, setShowAUMPopup] = useState(false); @@ -30,13 +37,13 @@ export const AccountSpotlight = () => { accountName = '--', accountNumber = '--', accountType = '--', - publicKeys = { pubKey: '', type: '' }, + publicKey = { base64: '', sigList: [], type: '' }, sequence = '--', tokens = { fungibleCount: 0, nonFungibleCount: 0 }, accountAum = { amount: 0, denom: '' }, } = accountInfo; - const { pubKey: publicKey, type: publicKeyType } = publicKeys; + const { base64, sigList, type: publicKeyType } = publicKey; const popupNoteKeyType = { visibility: { visible: showKeyPopup, setVisible: setShowKeyPopup }, @@ -123,6 +130,7 @@ export const AccountSpotlight = () => { popupNote?: PopupDataProps; link?: string; copy?: string; + button?: JSX.Element; } const cardData: ItemProps[] = [ @@ -145,23 +153,41 @@ export const AccountSpotlight = () => { { title: 'Number', value: String(accountNumber), popupNote: popupNoteNumber as PopupDataProps }, { title: 'Public Key', - value: maxLength(publicKey, 12, '3'), - copy: publicKey, + value: base64 && maxLength(base64, 12, '3'), + copy: base64 && base64, popupNote: popupNoteKeyType as PopupDataProps, + button: !base64 ? ( + + ) : ( + <> + ), }, { title: 'Sequence', value: String(sequence), popupNote: popupNoteSequence as PopupDataProps }, ]; return ( <> - {cardData.map((item) => ( - - - {item.link ? {item.value} : item.value} - {item.copy && } - - - ))} + <> + {cardData.map((item) => ( + + + {item.button && item.button} + {item.link ? {item.value} : item.value} + {item.copy && ( + + )} + + + ))} + + ); }; diff --git a/src/Pages/Accounts/Components/AccountTables/Components/AccountMultiSigModal.tsx b/src/Pages/Accounts/Components/AccountTables/Components/AccountMultiSigModal.tsx new file mode 100644 index 00000000..9c6e053c --- /dev/null +++ b/src/Pages/Accounts/Components/AccountTables/Components/AccountMultiSigModal.tsx @@ -0,0 +1,55 @@ +import { useState, useEffect } from 'react'; +import styled from 'styled-components'; +import { Modal } from 'Components'; +import { AccountInfo } from 'redux/features/account/accountSlice'; +import { Link } from 'react-router-dom'; + +const Title = styled.div` + text-align: center; + font-size: 2rem; + font-weight: ${({ theme }) => theme.FONT_WEIGHT_BOLD}; + margin: 20px 0; +`; + +const Description = styled.li` + color: ${({ theme }) => theme.FONT_TITLE_INFO}; + max-width: 500px; + margin: 0 auto; + margin-bottom: 20px; +`; + +interface MultiSigModalProps { + modalOpen: boolean; + onClose: Function; + data: AccountInfo['publicKey']['sigList']; +} + +export const AccountMultiSigModal = ({ modalOpen, onClose, data }: MultiSigModalProps) => { + const [isOpen, setIsOpen] = useState(false); + + useEffect(() => { + setIsOpen(modalOpen); + }, [modalOpen]); + + const handleModalClose = () => { + setIsOpen(false); + onClose(); + }; + + return ( + + <> + Generate a CSV of Transaction Information +
    + {data.map((account) => ( + + + {account.address} + + + ))} +
+ +
+ ); +}; diff --git a/src/Pages/Accounts/Components/AccountTables/Components/index.ts b/src/Pages/Accounts/Components/AccountTables/Components/index.ts index ef92f36c..4e277ba3 100644 --- a/src/Pages/Accounts/Components/AccountTables/Components/index.ts +++ b/src/Pages/Accounts/Components/AccountTables/Components/index.ts @@ -7,3 +7,4 @@ export * from './AccountRewards'; export * from './AccountUnbondings'; export * from './AccountAttributes'; export * from './AccountTxs'; +export * from './AccountMultiSigModal'; diff --git a/src/Pages/Tx/Components/TxInformation.js b/src/Pages/Tx/Components/TxInformation.js index 6d11549d..a439825b 100644 --- a/src/Pages/Tx/Components/TxInformation.js +++ b/src/Pages/Tx/Components/TxInformation.js @@ -59,9 +59,6 @@ const TxInformation = () => { decimal: totalFee.amount / 1e9 < 0.0001 ? 20 : 4, }); - // Signers is an object containing signers [array] and threshold [number] - we only need the signers array - const signerArray = signers?.signers; - const errorLogPopupNote = { visibility: { visible: showErrorLogPopup, setVisible: setShowErrorLogPopup }, icon: { name: 'HELP_OUTLINE', size: '1.7rem' }, @@ -96,10 +93,10 @@ const TxInformation = () => { { title: 'Signer(s)', - value: signerArray, // maxLength(signer, 24, 10), - list: signerArray.map((val) => maxLength(val, 12, '4')), - linkList: signerArray.map((val) => '/accounts/' + val), - copyList: signerArray, + value: signers, // maxLength(signer, 24, 10), + list: signers.map((val) => maxLength(val.address, 12, '4')), + linkList: signers.map((val) => '/accounts/' + val.address), + copyList: signers.map((val) => signers.address), }, { title: 'Feepayer', diff --git a/src/redux/features/account/accountSlice.ts b/src/redux/features/account/accountSlice.ts index b802ca7b..babfa478 100644 --- a/src/redux/features/account/accountSlice.ts +++ b/src/redux/features/account/accountSlice.ts @@ -4,7 +4,7 @@ import { RootState } from 'redux/app/store'; import { ACCOUNT_INFO_URL } from 'consts'; import { ajax } from '../api'; -interface AccountInfo { +export interface AccountInfo { accountAum?: { amount: string; denom: string; @@ -18,8 +18,12 @@ interface AccountInfo { data: string; }[]; isContract?: boolean; - publicKeys?: { - pubKey: string; + publicKey: { + base64: string; + sigList: { + address: string; + idx: number; + }[]; type: string; }; sequence?: number; @@ -198,7 +202,13 @@ interface AccountState { const initialState: AccountState = { // Account - accountInfo: {}, + accountInfo: { + publicKey: { + base64: '', + sigList: [], + type: '', + }, + }, accountInfoLoading: false, accountInfoFailure: false, // Account Assets diff --git a/src/redux/features/tx/txSlice.ts b/src/redux/features/tx/txSlice.ts index 41545c71..332cdf9c 100644 --- a/src/redux/features/tx/txSlice.ts +++ b/src/redux/features/tx/txSlice.ts @@ -43,9 +43,11 @@ export interface TxInfo { [key: string]: string; }; signers: { - signers: string[]; - threshold: number; - }; + address: string; + idx: number; + sequence: number; + type: string; + }[]; status: string; time: string; txHash: string; @@ -212,10 +214,7 @@ export const initialState: TxState = { height: 0, memo: '', monikers: {}, - signers: { - signers: [], - threshold: 0, - }, + signers: [], status: '', time: '', txHash: '', diff --git a/src/utils/table/formatTableData.js b/src/utils/table/formatTableData.js index feb059c2..b7c7b322 100644 --- a/src/utils/table/formatTableData.js +++ b/src/utils/table/formatTableData.js @@ -70,16 +70,12 @@ export const formatTableData = (data = [], tableHeaders) => { case 'signers': { // Signers is an object containing signers [array] and threshold [number] - we only need // the first value and the length to indicate the total number of signers - const signer = serverValue?.signers[0]; + const signer = serverValue?.[0].address; finalObj[dataName] = { value: maxLength(signer, 11, 3), link: `/accounts/${signer}`, - addTextToLink: - serverValue?.signers.length > 1 ? ` +${serverValue?.signers.length - 1}` : '', - hover: - serverValue?.signers.length <= 1 - ? signer - : `${serverValue.signers.length} total signers`, + addTextToLink: serverValue?.length > 1 ? ` +${serverValue?.length - 1}` : '', + hover: serverValue?.length <= 1 ? signer : `${serverValue.length} total signers`, }; break; }