diff --git a/CHANGELOG.md b/CHANGELOG.md index cab44b57c..03166918a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#220](https://github.com/alleslabs/celatone-frontend/pull/220) Add transactions table for account details page - [#222](https://github.com/alleslabs/celatone-frontend/pull/222) Add proposals of an account - [#221](https://github.com/alleslabs/celatone-frontend/pull/221) Add codes of an account - [#223](https://github.com/alleslabs/celatone-frontend/pull/223) Newer version of token card and format mechanism diff --git a/src/lib/components/table/TableTitle.tsx b/src/lib/components/table/TableTitle.tsx index 2a48f166c..20e449393 100644 --- a/src/lib/components/table/TableTitle.tsx +++ b/src/lib/components/table/TableTitle.tsx @@ -4,10 +4,16 @@ interface TableTitleProps { title: string; count: number; helperText?: string; + mb?: number | string; } -export const TableTitle = ({ title, count, helperText }: TableTitleProps) => ( - +export const TableTitle = ({ + title, + count, + helperText, + mb = "6", +}: TableTitleProps) => ( + {title} diff --git a/src/lib/data/constant.ts b/src/lib/data/constant.ts index 0b0b5f3d9..9d7967b2f 100644 --- a/src/lib/data/constant.ts +++ b/src/lib/data/constant.ts @@ -77,3 +77,14 @@ export const typeUrlDict = { }; export const DEFAULT_RPC_ERROR = "Invalid format, or Something went wrong"; + +export const DEFAULT_TX_FILTERS = { + isExecute: false, + isInstantiate: false, + isUpload: false, + isIbc: false, + isSend: false, + isMigrate: false, + isUpdateAdmin: false, + isClearAdmin: false, +}; diff --git a/src/lib/model/account.ts b/src/lib/model/account.ts index 361e2b27d..9e899647a 100644 --- a/src/lib/model/account.ts +++ b/src/lib/model/account.ts @@ -1,4 +1,5 @@ // TODO - Refactor Past txs query +import { DEFAULT_TX_FILTERS } from "lib/data"; import { useTxQueryCount } from "lib/pages/past-txs/query/useTxQuery"; import { useCodeListCountByWalletAddress } from "lib/services/codeService"; import { @@ -21,19 +22,10 @@ export const useAccountDetailsTableCounts = (walletAddress: HumanAddr) => { useInstantiatedCountByUserQuery(walletAddress); const { data: proposalsCount, refetch: refetchProposalsCount } = useProposalsCountByWalletAddress(walletAddress); - const { data: countTxs, refetch: refetchCountTxs } = useTxQueryCount( + const { data: txsCount, refetch: refetchTxsCount } = useTxQueryCount( walletAddress, "", - { - isExecute: false, - isInstantiate: false, - isUpload: false, - isIbc: false, - isSend: false, - isMigrate: false, - isUpdateAdmin: false, - isClearAdmin: false, - } + DEFAULT_TX_FILTERS ); return { @@ -41,13 +33,13 @@ export const useAccountDetailsTableCounts = (walletAddress: HumanAddr) => { codesCount, contractsAdminCount, contractsCount, - countTxs, + txsCount, proposalsCount, }, refetchCodesCount, refetchContractsAdminCount, refetchContractsCount, - refetchCountTxs, + refetchTxsCount, refetchProposalsCount, }; }; diff --git a/src/lib/pages/account-details/components/tables/transactions/TxsTableRow.tsx b/src/lib/pages/account-details/components/tables/transactions/TxsTableRow.tsx new file mode 100644 index 000000000..266e07a33 --- /dev/null +++ b/src/lib/pages/account-details/components/tables/transactions/TxsTableRow.tsx @@ -0,0 +1,109 @@ +import { + Box, + Flex, + Grid, + Icon, + Tag, + Text, + useDisclosure, +} from "@chakra-ui/react"; +import { useState } from "react"; +import { MdCheck, MdClose, MdKeyboardArrowDown } from "react-icons/md"; + +import { RenderActionMessages } from "lib/components/action-msg/ActionMessages"; +import { ExplorerLink } from "lib/components/ExplorerLink"; +import { TableRow } from "lib/components/table"; +import { AccordionTx } from "lib/components/table/AccordionTx"; +import type { PastTransaction } from "lib/types"; +import { dateFromNow, formatUTC } from "lib/utils"; + +interface TxsTableRowProps { + transaction: PastTransaction; + templateColumns: string; +} + +export const TxsTableRow = ({ + transaction, + templateColumns, +}: TxsTableRowProps) => { + const { isOpen, onToggle } = useDisclosure(); + const isAccordion = transaction.messages.length > 1; + const [showCopyButton, setShowCopyButton] = useState(false); + + return ( + + setShowCopyButton(true)} + onMouseLeave={() => setShowCopyButton(false)} + transition="all .25s ease-in-out" + cursor={isAccordion ? "pointer" : "default"} + > + + + + + + + + + + {transaction.isIbc && ( + + IBC + + )} + + + + + {transaction.created ? ( + + {formatUTC(transaction.created)} + + {`(${dateFromNow(transaction.created)})`} + + + ) : ( + N/A + )} + + + + {isAccordion && ( + + )} + + + {isAccordion && ( + + )} + + ); +}; diff --git a/src/lib/pages/account-details/components/tables/transactions/index.tsx b/src/lib/pages/account-details/components/tables/transactions/index.tsx new file mode 100644 index 000000000..856901bb9 --- /dev/null +++ b/src/lib/pages/account-details/components/tables/transactions/index.tsx @@ -0,0 +1,182 @@ +// TODO - Refactor: move common component out of pasttx +import { Box, Flex, Grid } from "@chakra-ui/react"; +import type { ChangeEvent } from "react"; +import { useState } from "react"; + +import { Loading } from "lib/components/Loading"; +import { Pagination } from "lib/components/pagination"; +import { usePaginator } from "lib/components/pagination/usePaginator"; +import { EmptyState } from "lib/components/state/EmptyState"; +import { TableContainer, TableHeader } from "lib/components/table"; +import { TableTitle } from "lib/components/table/TableTitle"; +import { ViewMore } from "lib/components/table/ViewMore"; +import { DEFAULT_TX_FILTERS } from "lib/data"; +import { FilterSelection } from "lib/pages/past-txs/components/FilterSelection"; +import { useTxQuery } from "lib/pages/past-txs/query/useTxQuery"; +import type { HumanAddr, Option, TxFilters } from "lib/types"; + +import { TxsTableRow } from "./TxsTableRow"; + +interface TransactionsTableProps { + walletAddress: HumanAddr; + scrollComponentId: string; + totalData: Option; + refetchCount: () => void; + onViewMore?: () => void; +} + +interface TransactionsTableBodyProps extends TransactionsTableProps { + filters: TxFilters; + filterSelected: string[]; +} + +const TransactionsTableBody = ({ + walletAddress, + scrollComponentId, + totalData, + refetchCount, + onViewMore, + filters, + filterSelected, +}: TransactionsTableBodyProps) => { + const { + pagesQuantity, + currentPage, + setCurrentPage, + pageSize, + setPageSize, + offset, + } = usePaginator({ + total: totalData, + initialState: { + pageSize: 10, + currentPage: 1, + isDisabled: false, + }, + }); + + const { data: transactions, isLoading } = useTxQuery( + walletAddress, + "", + filters, + onViewMore ? 5 : pageSize, + offset + ); + + const onPageChange = (nextPage: number) => { + refetchCount(); + setCurrentPage(nextPage); + }; + + const onPageSizeChange = (e: ChangeEvent) => { + const size = Number(e.target.value); + refetchCount(); + setPageSize(size); + setCurrentPage(1); + }; + + const templateColumns = "180px 70px minmax(360px, 1fr) max(250px) max(70px)"; + + if (isLoading) return ; + + if (!transactions?.length && filterSelected.length > 0) + return ( + + + + ); + + if (!transactions?.length) + return ( + + + + ); + + return ( + <> + + + Transaction Hash + + Messages + Timestamp + + + {transactions.map((transaction) => ( + + ))} + + {totalData && + (onViewMore + ? totalData > 5 && + : totalData > 10 && ( + + ))} + + ); +}; + +export const TransactionsTable = ( + transactionsTableProps: TransactionsTableProps +) => { + const [filters, setFilters] = useState(DEFAULT_TX_FILTERS); + + const handleSetFilters = (filter: string, bool: boolean) => { + setFilters((prevFilters) => ({ ...prevFilters, [filter]: bool })); + }; + + const filterSelected = Object.keys(filters).filter( + (key) => filters[key as keyof typeof filters] + ); + + const { totalData, onViewMore } = transactionsTableProps; + return ( + + + + {!onViewMore && ( + + )} + + + + ); +}; diff --git a/src/lib/pages/account-details/index.tsx b/src/lib/pages/account-details/index.tsx index 8360f7b0f..67fb6bf06 100644 --- a/src/lib/pages/account-details/index.tsx +++ b/src/lib/pages/account-details/index.tsx @@ -27,6 +27,7 @@ import { InstantiatedContractsTable, ProposalsTable, } from "./components/tables"; +import { TransactionsTable } from "./components/tables/transactions"; enum TabIndex { Overview, @@ -53,7 +54,7 @@ const AccountDetailsBody = ({ accountAddress }: AccountDetailsBodyProps) => { refetchCodesCount, refetchContractsAdminCount, refetchContractsCount, - // refetchCountTxs, + refetchTxsCount, refetchProposalsCount, } = useAccountDetailsTableCounts(accountAddress); @@ -95,8 +96,8 @@ const AccountDetailsBody = ({ accountAddress }: AccountDetailsBodyProps) => { Assets setTabIndex(TabIndex.Txs)} > Transactions @@ -136,8 +137,13 @@ const AccountDetailsBody = ({ accountAddress }: AccountDetailsBodyProps) => { Delegations {/* TODO: replace with the truncated Assets table */} Assets - {/* TODO: replace with the truncated Transactions table */} - Transactions + setTabIndex(TabIndex.Txs)} + /> { Assets - {/* TODO: replace with the full Transactions table */} - Transactions + { const { watch, setValue } = useForm({ defaultValues: { search: "", - filters: { - isExecute: false, - isInstantiate: false, - isUpload: false, - isIbc: false, - isSend: false, - isMigrate: false, - isUpdateAdmin: false, - isClearAdmin: false, - }, + filters: DEFAULT_TX_FILTERS, }, mode: "all", }); diff --git a/src/lib/types/tx/msg.ts b/src/lib/types/tx/msg.ts index 252dfbc64..ec4c3f46a 100644 --- a/src/lib/types/tx/msg.ts +++ b/src/lib/types/tx/msg.ts @@ -104,3 +104,14 @@ export interface DetailMigrate { msg: object; sender: Addr; } + +export interface TxFilters { + isExecute: boolean; + isInstantiate: boolean; + isUpload: boolean; + isIbc: boolean; + isSend: boolean; + isMigrate: boolean; + isUpdateAdmin: boolean; + isClearAdmin: boolean; +}