From b08b6f310908c1005e53f6563d0b4474e4df3657 Mon Sep 17 00:00:00 2001 From: Yashvardhan Jagnani <60016972+jagnani73@users.noreply.github.com> Date: Thu, 9 May 2024 04:19:37 +0530 Subject: [PATCH] wip: responsiveness (#166) --- .../AddressDetails/AddressDetails.tsx | 347 +++++++++--------- .../Molecules/BlockDetails/BlockDetails.tsx | 159 ++++---- src/components/Molecules/GasCard/GasCard.tsx | 30 +- .../Molecules/LatestBlocks/LatestBlocks.tsx | 83 +++-- .../Molecules/LatestPrice/LatestPrice.tsx | 16 +- .../LatestTransactions.stories.tsx | 17 + .../LatestTransactions/LatestTransactions.tsx | 140 +++++++ .../Molecules/SearchBar/SearchBar.tsx | 11 +- .../TransactionDetails/TransactionDetails.tsx | 181 ++++----- .../XYKPoolInformation/XYKPoolInformation.tsx | 217 +++++------ .../XYKTokenInformation.tsx | 201 +++++----- .../XYKWalletInformation.tsx | 188 ++++------ .../AddressActivityListView.tsx | 188 ++-------- .../TokenBalancesListView.tsx | 177 ++------- .../TokenTransfersListView.tsx | 283 +++++++------- .../XYKOverviewTransactionsListView.tsx | 144 ++------ .../XYK/XYKPoolListView/XYKPoolListView.tsx | 158 ++------ .../XYKPoolTransactionsListView.tsx | 144 ++------ .../XYK/XYKTokenListView/XYKTokenListView.tsx | 144 ++------ .../XYKTokenPoolListView.tsx | 141 ++----- .../XYKTokenTransactionsListView.tsx | 145 ++------ .../XYKWalletPoolListView.tsx | 141 ++----- .../XYKWalletPositionsListView.tsx | 137 ++----- .../XYKWalletTransactionsListView.tsx | 149 ++------ src/components/Shared/CardDetail.tsx | 20 + src/components/Shared/TableList.tsx | 111 ++++++ src/components/Shared/Transactions.tsx | 150 +------- src/components/Shared/index.tsx | 2 + src/components/ui/card.tsx | 2 +- src/components/ui/skeleton.tsx | 2 +- src/utils/types/molecules.types.ts | 16 +- src/utils/types/organisms.types.ts | 6 - src/utils/types/shared.types.ts | 21 +- 33 files changed, 1421 insertions(+), 2450 deletions(-) create mode 100644 src/components/Molecules/LatestTransactions/LatestTransactions.stories.tsx create mode 100644 src/components/Molecules/LatestTransactions/LatestTransactions.tsx create mode 100644 src/components/Shared/CardDetail.tsx create mode 100644 src/components/Shared/TableList.tsx diff --git a/src/components/Molecules/AddressDetails/AddressDetails.tsx b/src/components/Molecules/AddressDetails/AddressDetails.tsx index 13395996..41053c27 100644 --- a/src/components/Molecules/AddressDetails/AddressDetails.tsx +++ b/src/components/Molecules/AddressDetails/AddressDetails.tsx @@ -1,5 +1,5 @@ import { Address, TokenAvatar } from "@/components/Atoms"; -import { Card, CardContent, CardDescription } from "@/components/ui/card"; +import { Card } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { timestampParser } from "@/utils/functions"; @@ -21,13 +21,15 @@ import { DropdownMenuTrigger, } from "@radix-ui/react-dropdown-menu"; import { CaretDownIcon } from "@radix-ui/react-icons"; +import { CardDetail } from "@/components/Shared"; +import { type CardDetailProps } from "@/utils/types/shared.types"; export const AddressDetails: React.FC = ({ address, chain_name, }) => { const { covalentClient, selectedChain } = useGoldRush(); - + const [errorMessage, setErrorMessage] = useState(null); const [maybeResult, setMaybeResult] = useState< Option<{ balances: BalanceItem[]; @@ -54,9 +56,11 @@ export const AddressDetails: React.FC = ({ ), ]); if (summaryError.error) { + setErrorMessage(summaryError.error_message); throw summaryError; } if (balancesError.error) { + setErrorMessage(balancesError.error_message); throw balancesError; } const balances = balancesData.items; @@ -74,26 +78,24 @@ export const AddressDetails: React.FC = ({ }) ); } catch (error) { - console.error( - `Error fetching transactions summary for ${chain_name}:`, - error - ); + console.error(error); } })(); }, [address, chain_name]); return ( - + {maybeResult.match({ None: () => ( -
- - - - - - -
+ <> + {Array(6) + .fill(null) + .map(() => ( +
+ +
+ ))} + ), Some: ({ balances: [native, ...holdings], @@ -102,174 +104,167 @@ export const AddressDetails: React.FC = ({ latest_transaction, total_count, }, - }) => ( -
- {native.balance ? ( - <> -
- - {native.contract_ticker_symbol} BALANCE - - -
- - {calculatePrettyBalance( - native.balance, - native.contract_decimals, - false, - native.contract_decimals - )}{" "} - {native.contract_ticker_symbol} -
-
- -
- - {native.contract_ticker_symbol} VALUE - - -
- {prettifyCurrency( - (Number(native.balance) / - Math.pow( - 10, - native.contract_decimals - )) * - native.quote_rate - )} - - @{" "} - {prettifyCurrency( - native.quote_rate - )} - /{native.contract_ticker_symbol} - -
-
- - ) : ( - <> - )} - - - -

- Token Holdings ({holdings.length} tokens) - -

-
+ }) => + errorMessage ? ( +

{errorMessage}

+ ) : ( + ( + [ + { + heading: `${native.contract_ticker_symbol} BALANCE`, + content: ( + <> + + {calculatePrettyBalance( + native.balance ?? 0, + native.contract_decimals, + false, + native.contract_decimals + )}{" "} + {native.contract_ticker_symbol} + + ), + }, + { + heading: `${native.contract_ticker_symbol} VALUE`, + content: prettifyCurrency( + (Number(native.balance) / + Math.pow( + 10, + native.contract_decimals + )) * + native.quote_rate + ), + subtext: `@${prettifyCurrency( + native.quote_rate + )}/${native.contract_ticker_symbol}`, + }, + { + content: ( + + +

+ Token Holdings ( + {holdings.length} tokens) + +

+
- - {holdings.map( - ({ - balance, - contract_address, - contract_decimals, - contract_display_name, - contract_ticker_symbol, - logo_urls, - }) => ( - -
- -
- -
- - {contract_display_name} ( - {contract_ticker_symbol}) - - - {balance ? ( - <> - {calculatePrettyBalance( - balance, - contract_decimals, - true - )}{" "} - { - contract_ticker_symbol + + {holdings.map( + ({ + balance, + contract_address, + contract_decimals, + contract_display_name, + contract_ticker_symbol, + logo_urls, + }) => ( + - ) : ( - <> - )} - -
-
- ) - )} - -
-
- -
- - LATEST TRANSACTION - + className="mt-1 flex w-full items-center gap-x-4 border-t border-secondary-light px-2 py-1 first:border-t-0 dark:border-secondary-dark" + > +
+ +
-
-
- - {timestampParser( + + {calculatePrettyBalance( + balance, + contract_decimals, + true + )}{" "} + { + contract_ticker_symbol + } + + ) : null + } + /> + + ) + )} + + + + ), + }, + { + heading: "LATEST TRANSACTION", + content: ( +
+ ), + subtext: timestampParser( latest_transaction.block_signed_at, "relative" - )} - -
-
- -
- - EARLIEST TRANSACTION - - -
-
- - {timestampParser( + ), + }, + { + heading: "EARLIEST TRANSACTION", + content: ( +
+ ), + subtext: timestampParser( earliest_transaction.block_signed_at, "relative" - )} - -
-
- -
- TOTAL COUNT - -

{total_count.toLocaleString()} transactions

-
-
- ), + ), + }, + { + heading: "TOTAL COUNT", + content: `${total_count.toLocaleString()} transactions`, + }, + ] as CardDetailProps[] + ).map((props) => ( + + )) + ), })}
); diff --git a/src/components/Molecules/BlockDetails/BlockDetails.tsx b/src/components/Molecules/BlockDetails/BlockDetails.tsx index 2b7e21d2..29486f01 100644 --- a/src/components/Molecules/BlockDetails/BlockDetails.tsx +++ b/src/components/Molecules/BlockDetails/BlockDetails.tsx @@ -1,11 +1,13 @@ import { Address } from "@/components/Atoms"; -import { Card, CardDescription } from "@/components/ui/card"; +import { CardDetail } from "@/components/Shared"; +import { Card } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { timestampParser } from "@/utils/functions"; import { None, Some, type Option } from "@/utils/option"; import { useGoldRush } from "@/utils/store"; import { type BlockDetailsProps } from "@/utils/types/molecules.types"; +import { type CardDetailProps } from "@/utils/types/shared.types"; import { type Block } from "@covalenthq/client-sdk"; import { useEffect, useState } from "react"; @@ -39,94 +41,81 @@ export const BlockDetails: React.FC = ({ }, [chain_name, height]); return ( - + {maybeResult.match({ - None: () => , + None: () => ( + <> + {Array(8) + .fill(null) + .map(() => ( +
+ +
+ ))} + + ), Some: (block) => errorMessage ? ( -

{errorMessage}

+

{errorMessage}

) : ( -
-
- HEIGHT - -

- {block.height.toLocaleString()} -

-
- -
- SIGNED AT - -
-

- {timestampParser( - block.signed_at, - "descriptive" - )} -

-
-
- -
- BLOCK HASH - -
-
-
-
- -
- GAS USED - -
- {block.gas_used}{" "} - - {( - (block.gas_used / block.gas_limit) * - 100 - ).toFixed(2)} - % - -
-
- -
- GAS LIMIT - -
- {block.gas_limit.toLocaleString()} -
-
- -
- MINER ADDRESS - -
-
-
-
- -
- - BLOCK PARENT HASH - - -
-
-
-
- -
- EXTRA DATA - -
- {block.extra_data} -
-
-
+ ( + [ + { + heading: "HEIGHT", + content: block.height.toLocaleString(), + }, + { + heading: "SIGNED AT", + content: timestampParser( + block.signed_at, + "descriptive" + ), + }, + { + heading: "BLOCK HASH", + content: ( +
+ ), + }, + { + heading: "GAS USED", + content: block.gas_used, + subtext: `${( + (block.gas_used / block.gas_limit) * + 100 + ).toFixed(2)}%`, + }, + { + heading: "GAS LIMIT", + content: block.gas_limit.toLocaleString(), + }, + { + heading: "MINER ADDRESS", + content: ( +
+ ), + }, + { + heading: "BLOCK PARENT HASH", + content: ( +
+ ), + }, + { + heading: "EXTRA DATA", + content: block.extra_data, + }, + ] as CardDetailProps[] + ).map((props) => ( + + )) ), })} diff --git a/src/components/Molecules/GasCard/GasCard.tsx b/src/components/Molecules/GasCard/GasCard.tsx index 9f80740b..2105997a 100644 --- a/src/components/Molecules/GasCard/GasCard.tsx +++ b/src/components/Molecules/GasCard/GasCard.tsx @@ -58,22 +58,22 @@ export const GasCard: React.FC = ({ chain_name, event_type }) => { return (
-
- {maybeResult.match({ - None: () => , - Some: ({ base_fee }) => ( -

- ⛽ Base Fee:{" "} - {Math.round( - (Number(base_fee) ?? 0) / Math.pow(10, 9) - )}{" "} - Gwei -

- ), - })} -
+ {maybeResult.match({ + None: () => ( +
+ +
+ ), + Some: ({ base_fee }) => ( +

+ ⛽ Base Fee:{" "} + {Math.round((Number(base_fee) ?? 0) / Math.pow(10, 9))}{" "} + Gwei +

+ ), + })} -
+
{maybeResult.match({ None: () => Array(3) diff --git a/src/components/Molecules/LatestBlocks/LatestBlocks.tsx b/src/components/Molecules/LatestBlocks/LatestBlocks.tsx index bae6e96a..c1456450 100644 --- a/src/components/Molecules/LatestBlocks/LatestBlocks.tsx +++ b/src/components/Molecules/LatestBlocks/LatestBlocks.tsx @@ -1,12 +1,14 @@ import { Address } from "@/components/Atoms"; +import { CardDetail } from "@/components/Shared"; import { Button } from "@/components/ui/button"; -import { Card, CardDescription } from "@/components/ui/card"; +import { Card } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { timestampParser } from "@/utils/functions"; import { None, Some, type Option } from "@/utils/option"; import { useGoldRush } from "@/utils/store"; import { type LatestBlocksProps } from "@/utils/types/molecules.types"; +import { type CardDetailProps } from "@/utils/types/shared.types"; import { type Block } from "@covalenthq/client-sdk"; import { ExternalLinkIcon } from "@radix-ui/react-icons"; import { useEffect, useState } from "react"; @@ -62,44 +64,47 @@ export const LatestBlocks: React.FC = ({ key={block.height} className="flex w-full flex-col rounded border border-secondary-light p-2 dark:border-secondary-dark dark:bg-background-dark dark:text-white" > -
- BLOCK HEIGHT - -

- {block.height.toLocaleString()} -

-
- -
- SIGNED AT - -

- {timestampParser(block.signed_at, "relative")} -

-
- -
- BLOCK HASH - -
+ ), + }, + { + heading: "GAS USED", + content: `${( + (block.gas_used / block.gas_limit) * + 100 + ).toFixed(2)}%`, + }, + { + heading: "GAS LIMIT", + content: block.gas_limit.toLocaleString(), + }, + ] as CardDetailProps[] + ).map((props) => ( + -
- -
- GAS USED - {((block.gas_used / block.gas_limit) * 100).toFixed( - 2 - )} - % -
- -
- GAS LIMIT - - {block.gas_limit.toLocaleString()} -
+ ))} {on_view_details ? ( ) : ( diff --git a/src/components/Molecules/LatestPrice/LatestPrice.tsx b/src/components/Molecules/LatestPrice/LatestPrice.tsx index a7ef0e7f..b1f0635a 100644 --- a/src/components/Molecules/LatestPrice/LatestPrice.tsx +++ b/src/components/Molecules/LatestPrice/LatestPrice.tsx @@ -1,4 +1,5 @@ -import { Card, CardDescription } from "@/components/ui/card"; +import { CardDetail } from "@/components/Shared"; +import { Card } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { None, Some, type Option } from "@/utils/option"; @@ -46,15 +47,10 @@ export const LatestPrice: React.FC = ({ chain_name }) => {

{errorMessage}

) : (
-
- - {contract_ticker_symbol} PRICE - - -

- {pretty_price} -

-
+
), })} diff --git a/src/components/Molecules/LatestTransactions/LatestTransactions.stories.tsx b/src/components/Molecules/LatestTransactions/LatestTransactions.stories.tsx new file mode 100644 index 00000000..6983eac6 --- /dev/null +++ b/src/components/Molecules/LatestTransactions/LatestTransactions.stories.tsx @@ -0,0 +1,17 @@ +import { type Meta, type StoryObj } from "@storybook/react"; +import { LatestTransactions as LatestTransactionsComponent } from "./LatestTransactions"; + +type Story = StoryObj; + +const meta: Meta = { + title: "Molecules/Latest Transactions", + component: LatestTransactionsComponent, +}; + +export default meta; + +export const LatestTransactions: Story = { + args: { + chain_name: "eth-mainnet", + }, +}; diff --git a/src/components/Molecules/LatestTransactions/LatestTransactions.tsx b/src/components/Molecules/LatestTransactions/LatestTransactions.tsx new file mode 100644 index 00000000..267504f0 --- /dev/null +++ b/src/components/Molecules/LatestTransactions/LatestTransactions.tsx @@ -0,0 +1,140 @@ +import { Address } from "@/components/Atoms"; +import { CardDetail } from "@/components/Shared"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; +import { GRK_SIZES } from "@/utils/constants/shared.constants"; +import { timestampParser } from "@/utils/functions"; +import { None, Some, type Option } from "@/utils/option"; +import { useGoldRush } from "@/utils/store"; +import { type LatestTransactionsProps } from "@/utils/types/molecules.types"; +import { type CardDetailProps } from "@/utils/types/shared.types"; +import { type Transaction } from "@covalenthq/client-sdk"; +import { ExternalLinkIcon } from "@radix-ui/react-icons"; +import { useEffect, useState } from "react"; + +export const LatestTransactions: React.FC = ({ + chain_name, + limit = 5, + on_view_details, +}) => { + const { covalentClient } = useGoldRush(); + const [errorMessage, setErrorMessage] = useState(null); + const [maybeResult, setResult] = useState>(None); + + useEffect(() => { + (async () => { + setResult(None); + setErrorMessage(null); + try { + const { data: blockData, ...blockError } = + await covalentClient.BaseService.getBlockHeightsByPage( + chain_name, + timestampParser(Date(), "YYYY MM DD"), + "2100-01-01", + { + pageSize: 1, + } + ); + if (blockError.error) { + setErrorMessage(blockError.error_message); + throw blockError; + } + const latestBlock = blockData.items[0]; + const { data: txData, ...txError } = + await covalentClient.TransactionService.getTransactionsForBlock( + chain_name, + latestBlock.height - 2, + { + noLogs: true, + quoteCurrency: "USD", + withSafe: false, + } + ); + if (txError.error) { + setErrorMessage(txError.error_message); + throw txError; + } + setResult(new Some(txData.items.slice(-limit))); + } catch (error) { + console.error(error); + } + })(); + }, [chain_name, limit]); + + return maybeResult.match({ + None: () => ( + <> + {new Array(limit).fill(null).map(() => ( + + ))} + + ), + Some: (txs) => + errorMessage ? ( +

{errorMessage}

+ ) : ( + txs.map((tx) => ( + + {( + [ + { + heading: "TRANSACTION HASH", + content:
, + }, + { + heading: "BLOCK HEIGHT", + content: tx.block_height.toLocaleString(), + }, + { + heading: "FROM", + content: ( +
+ ), + }, + { + heading: "TO", + content: ( +
+ ), + }, + { + heading: "VALUE", + content: `${ + Number(tx.value) / + Math.pow( + 10, + tx.gas_metadata.contract_decimals + ) + } ${tx.gas_metadata.contract_ticker_symbol}`, + subtext: tx.pretty_value_quote, + }, + ] as CardDetailProps[] + ).map((props) => ( + + ))} + + {on_view_details ? ( + + ) : ( + <> + )} + + )) + ), + }); +}; diff --git a/src/components/Molecules/SearchBar/SearchBar.tsx b/src/components/Molecules/SearchBar/SearchBar.tsx index b713538a..6c7a76ce 100644 --- a/src/components/Molecules/SearchBar/SearchBar.tsx +++ b/src/components/Molecules/SearchBar/SearchBar.tsx @@ -69,20 +69,25 @@ export const SearchBar: React.FC = () => { return (
-
- +
+
+ +
+ setSearchInput(value)} - className="!border-accent-foreground" + className="!border-accent-foreground md:col-span-3" /> + diff --git a/src/components/Molecules/TransactionDetails/TransactionDetails.tsx b/src/components/Molecules/TransactionDetails/TransactionDetails.tsx index 69ffc9f9..c9e3fa58 100644 --- a/src/components/Molecules/TransactionDetails/TransactionDetails.tsx +++ b/src/components/Molecules/TransactionDetails/TransactionDetails.tsx @@ -1,11 +1,13 @@ import { Address } from "@/components/Atoms"; -import { Card, CardDescription } from "@/components/ui/card"; +import { CardDetail } from "@/components/Shared"; +import { Card } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { timestampParser } from "@/utils/functions"; import { None, Some, type Option } from "@/utils/option"; import { useGoldRush } from "@/utils/store"; import { type TransactionDetailsProps } from "@/utils/types/molecules.types"; +import { type CardDetailProps } from "@/utils/types/shared.types"; import { calculatePrettyBalance, type Transaction, @@ -50,120 +52,99 @@ export const TransactionDetails: React.FC = ({ }, [chain_name, tx_hash]); return ( - + {maybeResult.match({ - None: () => , + None: () => ( + <> + {Array(9) + .fill(null) + .map(() => ( +
+ +
+ ))} + + ), Some: (tx) => errorMessage ? ( -

{errorMessage}

+

{errorMessage}

) : ( -
-
- TX HASH - -
-
-
-
- -
- BLOCK - -

{tx.block_height.toLocaleString()}

-
- -
- SIGNED AT - -
-
- {timestampParser( - tx.block_signed_at, - "descriptive" - )}{" "} - - ( - {timestampParser( - tx.block_signed_at, - "relative" - )} - ) - -
-
-
- -
- BLOCK HASH - -
-
-
-
- -
- FROM - -
-
-
-
- -
- TO - -
-
-
-
- -
- VALUE - -
- {Number(tx.value) / + ( + [ + { + heading: "TX HASH", + content:
, + }, + { + heading: "BLOCK", + content: tx.block_height.toLocaleString(), + }, + { + heading: "SIGNED AT", + content: timestampParser( + tx.block_signed_at, + "descriptive" + ), + subtext: `(${timestampParser( + tx.block_signed_at, + "relative" + )})`, + }, + { + heading: "BLOCK HASH", + content: ( +
+ ), + }, + { + heading: "FROM", + content: ( +
+ ), + }, + { + heading: "TO", + content: ( +
+ ), + }, + { + heading: "VALUE", + content: `${ + Number(tx.value) / Math.pow( 10, tx.gas_metadata.contract_decimals - )}{" "} - {tx.gas_metadata.contract_ticker_symbol}{" "} - - {tx.pretty_value_quote} - -
-
- -
- TX FEE - -
- {calculatePrettyBalance( + ) + } ${tx.gas_metadata.contract_ticker_symbol}`, + subtext: tx.pretty_value_quote, + }, + { + heading: "TX FEE", + content: `${calculatePrettyBalance( BigInt(tx.fees_paid || 0)!, tx.gas_metadata.contract_decimals, true, 4 - )}{" "} - {tx.gas_metadata.contract_ticker_symbol}{" "} - - {tx.pretty_gas_quote} - -
-
- -
- GAS PRICE - -

- {calculatePrettyBalance( + )} ${tx.gas_metadata.contract_ticker_symbol}`, + subtext: tx.pretty_gas_quote, + }, + { + heading: "GAS PRICE", + content: `${calculatePrettyBalance( BigInt(tx.gas_price), tx.gas_metadata.contract_decimals, true, 10 - )}{" "} - {tx.gas_metadata.contract_ticker_symbol} -

-
-
+ )} ${tx.gas_metadata.contract_ticker_symbol}`, + }, + ] as CardDetailProps[] + ).map((props) => ( + + )) ), })}
diff --git a/src/components/Molecules/XYK/XYKPoolInformation/XYKPoolInformation.tsx b/src/components/Molecules/XYK/XYKPoolInformation/XYKPoolInformation.tsx index e12bbe37..4f664dfb 100644 --- a/src/components/Molecules/XYK/XYKPoolInformation/XYKPoolInformation.tsx +++ b/src/components/Molecules/XYK/XYKPoolInformation/XYKPoolInformation.tsx @@ -1,146 +1,123 @@ -import React, { useEffect } from "react"; +import { useEffect } from "react"; import { type Option, Some, None } from "@/utils/option"; import { useGoldRush } from "@/utils/store"; -import { copyToClipboard, truncate } from "@/utils/functions"; import { type PoolWithTimeseries } from "@covalenthq/client-sdk"; import { useState } from "react"; -import { useToast } from "../../../../utils/hooks"; -import { IconWrapper } from "@/components/Shared"; +import { CardDetail } from "@/components/Shared"; import { type XYKPoolInformationProps } from "@/utils/types/molecules.types"; import { Skeleton } from "@/components/ui/skeleton"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { type CardDetailProps } from "@/utils/types/shared.types"; +import { Address } from "@/components/Atoms"; export const XYKPoolInformation: React.FC = ({ - pool_address, chain_name, dex_name, + pool_address, pool_data, }) => { const [maybeResult, setResult] = useState>(None); - const { toast } = useToast(); + const [errorMessage, setErrorMessage] = useState(null); const { covalentClient } = useGoldRush(); - const handlePoolInformation = async () => { - setResult(None); - let response; - try { - response = await covalentClient.XykService.getPoolByAddress( - chain_name, - dex_name, - pool_address - ); - setResult(new Some(response.data.items[0])); - } catch (error) { - console.error(`Error fetching pool for ${chain_name}:`, error); - } - }; - - const InformationContainer: React.FC<{ - label: string; - text: string; - copy?: boolean; - }> = ({ label, text, copy = false }) => { - const [showCopy, setShowCopy] = useState(false); - - const handleCopyClick = () => { - toast({ - description: "Address copied!", - }); - copyToClipboard(text); - setShowCopy(true); - setTimeout(() => { - setShowCopy(false); - }, 3000); - }; - - return ( -
-

- {label} -

-
- {truncate(text)} - {showCopy ? ( - - ) : ( - copy && ( - handleCopyClick()} - /> - ) - )} -
-
- ); - }; - useEffect(() => { - if (pool_data) { - setResult(new Some(pool_data)); - return; - } - handlePoolInformation(); - }, [dex_name, pool_address, chain_name]); + (async () => { + if (pool_data) { + setResult(new Some(pool_data)); + return; + } - return ( -
- {maybeResult.match({ - None: () => { - return ( -
- {[1, 2, 3, 4].map((o, i) => { - return ( - - ); - })} -
+ setResult(None); + setErrorMessage(null); + try { + const { data, ...error } = + await covalentClient.XykService.getPoolByAddress( + chain_name, + dex_name, + pool_address ); - }, - Some: (result) => { - const token_0 = result.token_0; - const token_1 = result.token_1; + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items[0])); + } catch (error) { + console.error(error); + } + })(); + }, [chain_name, dex_name, pool_address, pool_data]); - return ( -
- - - - -
- ); - }, - })} + return ( + {maybeResult.match({ - None: () => , - Some: (result) => ( - - - + None: () => ( + <> + {Array(5) + .fill(null) + .map(() => ( +
+ +
+ ))} + ), + Some: ({ explorers, token_0, token_1 }) => + errorMessage ? ( +

{errorMessage}

+ ) : ( + <> + {( + [ + { + heading: "PAIR NAME", + content: `${token_0.contract_ticker_symbol}-${token_1.contract_ticker_symbol}`, + }, + { + heading: "PAIR ADDRESS", + content: ( +
+ ), + }, + { + heading: `${token_0.contract_ticker_symbol} ADDRESS`, + content: ( +
+ ), + }, + { + heading: `${token_1.contract_ticker_symbol} ADDRESS`, + content: ( +
+ ), + }, + ] as CardDetailProps[] + ).map((props) => ( + + ))} + + + + + + ), })} -
+
); }; diff --git a/src/components/Molecules/XYK/XYKTokenInformation/XYKTokenInformation.tsx b/src/components/Molecules/XYK/XYKTokenInformation/XYKTokenInformation.tsx index bf007fd7..12f8419c 100644 --- a/src/components/Molecules/XYK/XYKTokenInformation/XYKTokenInformation.tsx +++ b/src/components/Molecules/XYK/XYKTokenInformation/XYKTokenInformation.tsx @@ -1,145 +1,108 @@ -import React, { useEffect } from "react"; +import { useEffect } from "react"; import { type Option, Some, None } from "@/utils/option"; import { useGoldRush } from "@/utils/store"; -import { copyToClipboard, truncate } from "@/utils/functions"; import { type TokenV2VolumeWithChartData } from "@covalenthq/client-sdk"; import { useState } from "react"; -import { useToast } from "../../../../utils/hooks"; -import { IconWrapper } from "@/components/Shared"; +import { CardDetail } from "@/components/Shared"; import { type XYKTokenInformationProps } from "@/utils/types/molecules.types"; import { Skeleton } from "@/components/ui/skeleton"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { type CardDetailProps } from "@/utils/types/shared.types"; +import { Address } from "@/components/Atoms"; export const XYKTokenInformation: React.FC = ({ - token_address, chain_name, dex_name, + token_address, token_data, }) => { const [maybeResult, setResult] = useState>(None); - const { toast } = useToast(); + const [errorMessage, setErrorMessage] = useState(null); const { covalentClient } = useGoldRush(); - const handlePoolInformation = async () => { - setResult(None); - let response; - try { - response = await covalentClient.XykService.getLpTokenView( - chain_name, - dex_name, - token_address - ); - setResult(new Some(response.data.items[0])); - } catch (error) { - console.error(`Error fetching token for ${chain_name}:`, error); - } - }; - - const InformationContainer: React.FC<{ - label: string; - text: string; - copy?: boolean; - }> = ({ label, text, copy = false }) => { - const [showCopy, setShowCopy] = useState(false); - - const handleCopyClick = () => { - toast({ - description: "Address copied!", - }); - copyToClipboard(text); - setShowCopy(true); - setTimeout(() => { - setShowCopy(false); - }, 3000); - }; - - return ( -
-

- {label} -

-
- {truncate(text)} - {showCopy ? ( - - ) : ( - copy && ( - handleCopyClick()} - /> - ) - )} -
-
- ); - }; - useEffect(() => { - if (token_data) { - setResult(new Some(token_data)); - return; - } - handlePoolInformation(); - }, [dex_name, token_address, chain_name]); + (async () => { + if (token_data) { + setResult(new Some(token_data)); + return; + } + + setResult(None); + setErrorMessage(null); + try { + const { data, ...error } = + await covalentClient.XykService.getLpTokenView( + chain_name, + dex_name, + token_address + ); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items[0])); + } catch (error) { + console.error(error); + } + })(); + }, [chain_name, dex_name, token_address, token_data]); return ( - <> -
- {maybeResult.match({ - None: () => { - return ( -
- {[1, 2, 3, 4].map((o, i) => { - return ( - - ); - })} -
- ); - }, - Some: (result) => { - return ( -
- - - + {maybeResult.match({ + None: () => ( + <> + {Array(4) + .fill(null) + .map(() => ( +
+ +
+ ))} + + ), + Some: ({ contract_ticker_symbol, contract_name, explorers }) => + errorMessage ? ( +

{errorMessage}

+ ) : ( + <> + {( + [ + { + heading: "SYMBOL", + content: contract_ticker_symbol, + }, + { + heading: "NAME", + content: contract_name, + }, + { + heading: "ADDRESS", + content: ( +
+ ), + }, + ] as CardDetailProps[] + ).map((props) => ( + -
- ); - }, - })} + ))} - {maybeResult.match({ - None: () => , - Some: (result) => ( - - - + + + + ), - })} -
- + })} + ); }; diff --git a/src/components/Molecules/XYK/XYKWalletInformation/XYKWalletInformation.tsx b/src/components/Molecules/XYK/XYKWalletInformation/XYKWalletInformation.tsx index 39cfc98c..f5c1030c 100644 --- a/src/components/Molecules/XYK/XYKWalletInformation/XYKWalletInformation.tsx +++ b/src/components/Molecules/XYK/XYKWalletInformation/XYKWalletInformation.tsx @@ -1,139 +1,101 @@ -import React, { useEffect } from "react"; +import { useEffect } from "react"; import { type Option, Some, None } from "@/utils/option"; import { useGoldRush } from "@/utils/store"; -import { copyToClipboard } from "@/utils/functions"; import { prettifyCurrency, type ExchangeTransaction, } from "@covalenthq/client-sdk"; import { useState } from "react"; -import { useToast } from "../../../../utils/hooks"; -import { IconWrapper } from "@/components/Shared"; +import { CardDetail } from "@/components/Shared"; import { type XYKWalletInformationProps } from "@/utils/types/molecules.types"; import { Skeleton } from "@/components/ui/skeleton"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; +import { Card } from "@/components/ui/card"; +import { type CardDetailProps } from "@/utils/types/shared.types"; export const XYKWalletInformation: React.FC = ({ - wallet_address, chain_name, dex_name, + wallet_address, wallet_data, }) => { const [maybeResult, setResult] = useState>(None); - const { toast } = useToast(); + const [errorMessage, setErrorMessage] = useState(null); const { covalentClient } = useGoldRush(); - const handlePoolInformation = async () => { - setResult(None); - let response; - try { - response = - await covalentClient.XykService.getTransactionsForAccountAddress( - chain_name, - dex_name, - wallet_address - ); - setResult(new Some(response.data.items)); - } catch (error) { - console.error(`Error fetching token for ${chain_name}:`, error); - } - }; - - const InformationContainer: React.FC<{ - label: string; - text: string; - copy?: boolean; - }> = ({ label, text, copy = false }) => { - const [showCopy, setShowCopy] = useState(false); + useEffect(() => { + (async () => { + if (wallet_data) { + setResult(new Some(wallet_data)); + return; + } - const handleCopyClick = () => { - toast({ - description: "Address copied!", - }); - copyToClipboard(text); - setShowCopy(true); - setTimeout(() => { - setShowCopy(false); - }, 3000); - }; + setResult(None); + setErrorMessage(null); + try { + const { data, ...error } = + await covalentClient.XykService.getTransactionsForAccountAddress( + chain_name, + dex_name, + wallet_address + ); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items)); + } catch (error) { + console.error(error); + } + })(); + }, [chain_name, dex_name, wallet_address, wallet_data]); - return ( -
-
-

{text}

- {showCopy ? ( - + return ( + + {maybeResult.match({ + None: () => ( + <> + {Array(2) + .fill(null) + .map(() => ( +
+ +
+ ))} + + ), + Some: (result) => + errorMessage ? ( +

{errorMessage}

) : ( - copy && ( - handleCopyClick()} + ( + [ + { + heading: "TOTAL VALUE SWAPPED", + content: prettifyCurrency( + result + .filter((o) => o.act === "SWAP") + .reduce((acc, obj) => { + const valueQuote = + obj.total_quote; + return acc + valueQuote; + }, 0) + ), + }, + { + heading: "TOTAL TRANSACTIONS", + content: result.length.toLocaleString(), + }, + ] as CardDetailProps[] + ).map((props) => ( + - ) - )} -
-
- {label} -
-
- ); - }; - - useEffect(() => { - if (wallet_data) { - setResult(new Some(wallet_data)); - return; - } - handlePoolInformation(); - }, [dex_name, wallet_address, chain_name]); - - return ( - <> -
- {maybeResult.match({ - None: () => { - return ( -
- {[1, 2].map((o, i) => { - return ( - - ); - })} -
- ); - }, - Some: (result) => { - const sumOfValueQuotes = result - .filter((o) => o.act === "SWAP") - .reduce((acc, obj) => { - const valueQuote = obj.total_quote; - return acc + valueQuote; - }, 0); - return ( -
- - -
- ); - }, - })} -
- + )) + ), + })} + ); }; diff --git a/src/components/Organisms/AddressActivityListView/AddressActivityListView.tsx b/src/components/Organisms/AddressActivityListView/AddressActivityListView.tsx index 0be5c7d4..ace766c8 100644 --- a/src/components/Organisms/AddressActivityListView/AddressActivityListView.tsx +++ b/src/components/Organisms/AddressActivityListView/AddressActivityListView.tsx @@ -1,28 +1,12 @@ import { type Option, None, Some } from "@/utils/option"; import { type ChainActivityEvent } from "@covalenthq/client-sdk"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; +import { type ColumnDef } from "@tanstack/react-table"; import { useEffect, useState } from "react"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { Checkbox } from "@/components/ui/checkbox"; import { AccountCard } from "@/components/Molecules"; import { Skeleton } from "@/components/ui/skeleton"; import { timestampParser } from "@/utils/functions"; import { TokenAvatar } from "@/components/Atoms"; -import { SkeletonTable, TableHeaderSorting } from "@/components/Shared"; +import { TableHeaderSorting, TableList } from "@/components/Shared"; import { IconWrapper } from "@/components/Shared"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { useGoldRush } from "@/utils/store"; @@ -30,87 +14,36 @@ import { type AddressActivityListViewProps } from "@/utils/types/organisms.types export const AddressActivityListView: React.FC< AddressActivityListViewProps -> = ({ - address, - get_all_row_selection, - get_row_selection_state, - row_selection_state, -}) => { +> = ({ address }) => { const { covalentClient } = useGoldRush(); - const [sorting, setSorting] = useState([]); - const [rowSelection, setRowSelection] = useState( - row_selection_state ? row_selection_state : {} - ); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); - - useEffect(() => { - maybeResult.match({ - None: () => null, - Some: (resp) => { - const chains_selected: ChainActivityEvent[] = []; - for (const i in rowSelection) { - const index: number = parseInt(i); - chains_selected.push(resp[index]); - } - if (get_all_row_selection) { - get_all_row_selection(chains_selected); - } - }, - }); - if (get_row_selection_state) { - get_row_selection_state(rowSelection); - } - }, [maybeResult, rowSelection, row_selection_state]); + const [errorMessage, setErrorMessage] = useState(null); useEffect(() => { (async () => { setResult(None); - let response; + setErrorMessage(null); try { - response = await covalentClient.BaseService.getAddressActivity( - address.trim(), - { - testnets: true, - } - ); - setError({ error: false, error_message: "" }); - setResult(new Some(response.data.items)); - } catch (exception) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + const { data, ...error } = + await covalentClient.BaseService.getAddressActivity( + address.trim(), + { + testnets: true, + } + ); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items)); + } catch (error) { + console.error(error); } })(); }, [address]); const columns: ColumnDef[] = [ - { - id: "select", - header: ({ table }) => ( - { - table.toggleAllPageRowsSelected(!!value); - }} - aria-label="Select all" - /> - ), - cell: ({ row }) => ( - { - row.toggleSelected(!!value); - }} - aria-label="Select row" - /> - ), - enableSorting: false, - enableHiding: false, - }, { accessorKey: "label", header: ({ column }) => ( @@ -174,62 +107,6 @@ export const AddressActivityListView: React.FC< }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => - error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No results. - - - ), - }); - return (
@@ -290,28 +167,11 @@ export const AddressActivityListView: React.FC<
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={columns} + errorMessage={errorMessage} + maybeData={maybeResult} + />
); }; diff --git a/src/components/Organisms/TokenBalancesListView/TokenBalancesListView.tsx b/src/components/Organisms/TokenBalancesListView/TokenBalancesListView.tsx index a9e941ab..208bf8f9 100644 --- a/src/components/Organisms/TokenBalancesListView/TokenBalancesListView.tsx +++ b/src/components/Organisms/TokenBalancesListView/TokenBalancesListView.tsx @@ -14,22 +14,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { type ColumnDef } from "@tanstack/react-table"; import { Skeleton } from "@/components/ui/skeleton"; import { TokenAvatar } from "@/components/Atoms"; import { Button } from "@/components/ui/button"; @@ -38,8 +23,8 @@ import { AccountCard } from "@/components/Molecules"; import { BalancePriceDelta, IconWrapper, - SkeletonTable, TableHeaderSorting, + TableList, } from "@/components/Shared"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { useGoldRush } from "@/utils/store"; @@ -56,66 +41,51 @@ export const TokenBalancesListView: React.FC = ({ on_transfer_click, }) => { const { covalentClient, chains } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "pretty_quote", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); const [filterResult, setFilterResult] = useState>(None); const [windowWidth, setWindowWidth] = useState(0); - const handleTokenBalances = async (_address: string) => { - setResult(None); - const promises = chain_names.map(async (chain) => { - let response; - try { - response = - await covalentClient.BalanceService.getTokenBalancesForWalletAddress( - chain, - _address.trim() - ); - - setError({ error: false, error_message: "" }); - return response.data.items.map((o) => { - return { ...o, chain }; - }); - } catch (error) { - console.error(`Error fetching balances for ${chain}:`, error); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); - return []; - } - }); - - const results = await Promise.all(promises); - setResult(new Some(results.flat())); - }; - useEffect(() => { setWindowWidth(window.innerWidth); - const handleResize = () => { setWindowWidth(window.innerWidth); }; - window.addEventListener("resize", handleResize); - return () => { window.removeEventListener("resize", handleResize); }; }, []); useEffect(() => { - handleTokenBalances(address); + (async () => { + setResult(None); + setErrorMessage(null); + const results = await Promise.all( + chain_names.map(async (chain) => { + try { + const { data, ...error } = + await covalentClient.BalanceService.getTokenBalancesForWalletAddress( + chain, + address.trim() + ); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + return data.items.map((o) => { + return { ...o, chain }; + }); + } catch (error) { + console.error(error); + return []; + } + }) + ); + setResult(new Some(results.flat())); + })(); }, [chain_names, address]); useEffect(() => { @@ -489,62 +459,6 @@ export const TokenBalancesListView: React.FC = ({ }, ]; - const table = useReactTable({ - data: filterResult.match({ - None: () => [], - Some: (result) => result, - }), - columns: windowWidth < 700 ? mobile_columns : columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = filterResult.match({ - None: () => , - Some: () => - error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No results. - - - ), - }); - return (
@@ -595,28 +509,17 @@ export const TokenBalancesListView: React.FC = ({
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={windowWidth < 700 ? mobile_columns : columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "pretty_quote", + desc: true, + }, + ]} + />
); }; diff --git a/src/components/Organisms/TokenTransfersListView/TokenTransfersListView.tsx b/src/components/Organisms/TokenTransfersListView/TokenTransfersListView.tsx index a2b2e43f..f12b2adc 100644 --- a/src/components/Organisms/TokenTransfersListView/TokenTransfersListView.tsx +++ b/src/components/Organisms/TokenTransfersListView/TokenTransfersListView.tsx @@ -55,145 +55,6 @@ import { } from "@/utils/types/organisms.types"; import { useGoldRush } from "@/utils/store"; -const columns: ColumnDef[] = [ - { - accessorKey: "block_signed_at", - header: ({ column }) => ( -
- -
- ), - cell: ({ row }) => { - const t = row.getValue("block_signed_at") as string; - - return
{timestampParser(t, "relative")}
; - }, - }, - { - accessorKey: "from_address", - header: "From", - cell: ({ row }) => { - return ( -
- - {truncate(row.getValue("from_address"))} -
- ); - }, - }, - { - accessorKey: "to_address", - header: "To", - cell: ({ row }) => { - return ( -
- - {truncate(row.getValue("to_address"))} -
- ); - }, - }, - { - accessorKey: "transfer_type", - header: "In/Out", - cell: ({ row }) => { - return {row.original.transfers[0].transfer_type}; - }, - }, - { - id: "tokenAmount", - accessorKey: "delta", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const transfer = row.original.transfers[0]; - if (transfer) { - return ( -
- {calculatePrettyBalance( - transfer?.delta ?? 0, - transfer?.contract_decimals - )}{" "} - {transfer?.contract_ticker_symbol} -
- ); - } - return null; - }, - }, - { - id: "value", - accessorKey: "delta_quote", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - return ( -
- {prettifyCurrency( - row.original.transfers[0].delta_quote, - 2, - "USD", - true - )} -
- ); - }, - }, - { - accessorKey: "tx_hash", - header: ({ column }) => ( -
- -
- ), - cell: ({ row }) => { - const txHash: string = row.getValue("tx_hash"); - return ( - - {truncate(txHash)} - - - ); - }, - }, -]; - export const TokenTransfersListView: React.FC = ({ chain_name, address, @@ -202,7 +63,6 @@ export const TokenTransfersListView: React.FC = ({ const { covalentClient, chains } = useGoldRush(); const [sorting, setSorting] = useState([]); - const [rowSelection, setRowSelection] = useState({}); const [paginator, setPaginator] = useState({ pageNumber: 0, pageSize: 10, @@ -297,6 +157,147 @@ export const TokenTransfersListView: React.FC = ({ })(); }, [address, contract_address, chain_name, paginator]); + const columns: ColumnDef[] = [ + { + accessorKey: "block_signed_at", + header: ({ column }) => ( +
+ +
+ ), + cell: ({ row }) => { + const t = row.getValue("block_signed_at") as string; + + return ( +
{timestampParser(t, "relative")}
+ ); + }, + }, + { + accessorKey: "from_address", + header: "From", + cell: ({ row }) => { + return ( +
+ + {truncate(row.getValue("from_address"))} +
+ ); + }, + }, + { + accessorKey: "to_address", + header: "To", + cell: ({ row }) => { + return ( +
+ + {truncate(row.getValue("to_address"))} +
+ ); + }, + }, + { + accessorKey: "transfer_type", + header: "In/Out", + cell: ({ row }) => { + return {row.original.transfers[0].transfer_type}; + }, + }, + { + id: "tokenAmount", + accessorKey: "delta", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const transfer = row.original.transfers[0]; + if (transfer) { + return ( +
+ {calculatePrettyBalance( + transfer?.delta ?? 0, + transfer?.contract_decimals + )}{" "} + {transfer?.contract_ticker_symbol} +
+ ); + } + return null; + }, + }, + { + id: "value", + accessorKey: "delta_quote", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + return ( +
+ {prettifyCurrency( + row.original.transfers[0].delta_quote, + 2, + "USD", + true + )} +
+ ); + }, + }, + { + accessorKey: "tx_hash", + header: ({ column }) => ( +
+ +
+ ), + cell: ({ row }) => { + const txHash: string = row.getValue("tx_hash"); + return ( + + {truncate(txHash)} + + + ); + }, + }, + ]; + const table = useReactTable({ data: maybeResult.match({ None: () => [], @@ -306,10 +307,8 @@ export const TokenTransfersListView: React.FC = ({ onSortingChange: setSorting, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, state: { sorting, - rowSelection, }, }); diff --git a/src/components/Organisms/XYK/XYKOverviewTransactionsListView/XYKOverviewTransactionsListView.tsx b/src/components/Organisms/XYK/XYKOverviewTransactionsListView/XYKOverviewTransactionsListView.tsx index cce38b61..9079a6a3 100644 --- a/src/components/Organisms/XYK/XYKOverviewTransactionsListView/XYKOverviewTransactionsListView.tsx +++ b/src/components/Organisms/XYK/XYKOverviewTransactionsListView/XYKOverviewTransactionsListView.tsx @@ -1,23 +1,8 @@ import { type Option, None, Some } from "@/utils/option"; import { type ExchangeTransaction } from "@covalenthq/client-sdk"; import { POOL_TRANSACTION_MAP } from "@/utils/constants/shared.constants"; -import { Fragment, useEffect, useState } from "react"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { useEffect, useState } from "react"; +import { type ColumnDef } from "@tanstack/react-table"; import { timestampParser } from "@/utils/functions"; import { Badge } from "@/components/ui/badge"; import { type XYKOverviewTransactionsListViewProps } from "@/utils/types/organisms.types"; @@ -26,8 +11,8 @@ import { handleTokenTransactions } from "@/utils/functions/pretty-exchange-amoun import { handleExchangeType } from "@/utils/functions/exchange-type"; import { IconWrapper, - SkeletonTable, TableHeaderSorting, + TableList, } from "@/components/Shared"; import { DropdownMenu, @@ -48,36 +33,27 @@ export const XYKOverviewTransactionsListView: React.FC< on_goldrush_receipt_click, }) => { const { covalentClient } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "block_signed_at", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); useEffect(() => { - setResult(None); (async () => { - let response; try { - response = + setResult(None); + setErrorMessage(null); + const { data, ...error } = await covalentClient.XykService.getTransactionsForDex( chain_name, dex_name ); - setResult(new Some(response.data.items)); - setError({ error: false, error_message: "" }); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items)); } catch (error) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + console.error(error); } })(); }, [dex_name, chain_name]); @@ -332,91 +308,19 @@ export const XYKOverviewTransactionsListView: React.FC< }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => { - return error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => { - return ( - - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - - ); - }) - ) : ( - - - No results. - - - ); - }, - }); - return (
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "block_signed_at", + desc: true, + }, + ]} + />
); }; diff --git a/src/components/Organisms/XYK/XYKPoolListView/XYKPoolListView.tsx b/src/components/Organisms/XYK/XYKPoolListView/XYKPoolListView.tsx index c7b3d0eb..583c0b6a 100644 --- a/src/components/Organisms/XYK/XYKPoolListView/XYKPoolListView.tsx +++ b/src/components/Organisms/XYK/XYKPoolListView/XYKPoolListView.tsx @@ -8,28 +8,13 @@ import { DropdownMenuLabel, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { type ColumnDef } from "@tanstack/react-table"; import { TokenAvatar } from "@/components/Atoms"; import { Button } from "@/components/ui/button"; import { IconWrapper, - SkeletonTable, TableHeaderSorting, + TableList, } from "@/components/Shared"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { useGoldRush } from "@/utils/store"; @@ -52,16 +37,8 @@ export const XYKPoolListView: React.FC = ({ page_size = 10, }) => { const { covalentClient } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "total_liquidity_quote", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); const [windowWidth, setWindowWidth] = useState(0); const [pagination, setPagination] = useState({ page_number: 1, @@ -80,38 +57,35 @@ export const XYKPoolListView: React.FC = ({ useEffect(() => { (async () => { setResult(None); - let response; + setErrorMessage(null); try { - response = await covalentClient.XykService.getPools( - chain_name, - dex_name, - { - pageNumber: pagination.page_number - 1, - pageSize: page_size, - } - ); - setHasMore(response.data.pagination.has_more); - setError({ error: false, error_message: "" }); - setResult(new Some(response.data.items)); - } catch (exception) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + const { data, ...error } = + await covalentClient.XykService.getPools( + chain_name, + dex_name, + { + pageNumber: pagination.page_number - 1, + pageSize: page_size, + } + ); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setHasMore(data.pagination.has_more); + setResult(new Some(data.items)); + } catch (error) { + console.error(error); } })(); }, [chain_name, dex_name, pagination]); useEffect(() => { setWindowWidth(window.innerWidth); - const handleResize = () => { setWindowWidth(window.innerWidth); }; - window.addEventListener("resize", handleResize); - return () => { window.removeEventListener("resize", handleResize); }; @@ -463,86 +437,20 @@ export const XYKPoolListView: React.FC = ({ }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns: windowWidth < 700 ? mobile_columns : columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => - error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No results. - - - ), - }); - return (
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={windowWidth < 700 ? mobile_columns : columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "total_liquidity_quote", + desc: true, + }, + ]} + /> + { const { covalentClient } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "block_signed_at", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); useEffect(() => { - setResult(None); (async () => { - let response; + setResult(None); + setErrorMessage(null); try { - response = + const { data, ...error } = await covalentClient.XykService.getTransactionsForExchange( chain_name, dex_name, pool_address.trim() ); - setResult(new Some(response.data.items)); - setError({ error: false, error_message: "" }); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items)); } catch (error) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + console.error(error); } })(); }, [pool_address, dex_name, chain_name]); @@ -334,91 +310,19 @@ export const XYKPoolTransactionsListView: React.FC< }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => { - return error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => { - return ( - - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - - ); - }) - ) : ( - - - No results. - - - ); - }, - }); - return (
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "block_signed_at", + desc: true, + }, + ]} + />
); }; diff --git a/src/components/Organisms/XYK/XYKTokenListView/XYKTokenListView.tsx b/src/components/Organisms/XYK/XYKTokenListView/XYKTokenListView.tsx index bec458ff..bf3e6616 100644 --- a/src/components/Organisms/XYK/XYKTokenListView/XYKTokenListView.tsx +++ b/src/components/Organisms/XYK/XYKTokenListView/XYKTokenListView.tsx @@ -8,29 +8,14 @@ import { DropdownMenuLabel, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { type ColumnDef } from "@tanstack/react-table"; import { TokenAvatar } from "@/components/Atoms"; import { Button } from "@/components/ui/button"; import { BalancePriceDelta, IconWrapper, - SkeletonTable, TableHeaderSorting, + TableList, } from "@/components/Shared"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { useGoldRush } from "@/utils/store"; @@ -52,16 +37,8 @@ export const XYKTokenListView: React.FC = ({ page_size = 10, }) => { const { covalentClient } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "total_volume_24h_quote", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); const [windowWidth, setWindowWidth] = useState(0); const [pagination, setPagination] = useState({ page_number: 1, @@ -80,9 +57,9 @@ export const XYKTokenListView: React.FC = ({ useEffect(() => { (async () => { setResult(None); - let response; + setErrorMessage(null); try { - response = + const { data, ...error } = await covalentClient.XykService.getNetworkExchangeTokens( chain_name, dex_name, @@ -91,28 +68,25 @@ export const XYKTokenListView: React.FC = ({ pageSize: page_size, } ); - setHasMore(response.data.pagination.has_more); - setError({ error: false, error_message: "" }); - setResult(new Some(response.data.items)); - } catch (exception) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setHasMore(data.pagination.has_more); + setResult(new Some(data.items)); + } catch (error) { + console.error(error); + return []; } })(); }, [chain_name, dex_name, pagination]); useEffect(() => { setWindowWidth(window.innerWidth); - const handleResize = () => { setWindowWidth(window.innerWidth); }; - window.addEventListener("resize", handleResize); - return () => { window.removeEventListener("resize", handleResize); }; @@ -421,86 +395,20 @@ export const XYKTokenListView: React.FC = ({ }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns: windowWidth < 700 ? mobile_columns : columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => - error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No results. - - - ), - }); - return (
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={windowWidth < 700 ? mobile_columns : columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "total_volume_24h_quote", + desc: true, + }, + ]} + /> + = ({ token_address, }) => { const { covalentClient } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "total_liquidity_quote", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); const [windowWidth, setWindowWidth] = useState(0); useEffect(() => { (async () => { setResult(None); - let response; + setErrorMessage(null); try { - response = + const { data, ...error } = await covalentClient.XykService.getPoolsForTokenAddress( chain_name, token_address, @@ -71,27 +49,23 @@ export const XYKTokenPoolListView: React.FC = ({ dexName: dex_name, } ); - setError({ error: false, error_message: "" }); - setResult(new Some(response.data.items)); - } catch (exception) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items)); + } catch (error) { + console.error(error); } })(); }, [chain_name, dex_name]); useEffect(() => { setWindowWidth(window.innerWidth); - const handleResize = () => { setWindowWidth(window.innerWidth); }; - window.addEventListener("resize", handleResize); - return () => { window.removeEventListener("resize", handleResize); }; @@ -442,86 +416,19 @@ export const XYKTokenPoolListView: React.FC = ({ }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns: windowWidth < 700 ? mobile_columns : columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => - error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No results. - - - ), - }); - return (
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={windowWidth < 700 ? mobile_columns : columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "total_liquidity_quote", + desc: true, + }, + ]} + />
); }; diff --git a/src/components/Organisms/XYK/XYKTokenTransactionsListView/XYKTokenTransactionsListView.tsx b/src/components/Organisms/XYK/XYKTokenTransactionsListView/XYKTokenTransactionsListView.tsx index a4382283..f74325cb 100644 --- a/src/components/Organisms/XYK/XYKTokenTransactionsListView/XYKTokenTransactionsListView.tsx +++ b/src/components/Organisms/XYK/XYKTokenTransactionsListView/XYKTokenTransactionsListView.tsx @@ -1,23 +1,9 @@ import { type Option, None, Some } from "@/utils/option"; import { type ExchangeTransaction } from "@covalenthq/client-sdk"; import { POOL_TRANSACTION_MAP } from "@/utils/constants/shared.constants"; -import { Fragment, useEffect, useState } from "react"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { useEffect, useState } from "react"; +import { type ColumnDef } from "@tanstack/react-table"; + import { timestampParser } from "@/utils/functions"; import { Badge } from "@/components/ui/badge"; import { type XYKTokenTransactionsListViewProps } from "@/utils/types/organisms.types"; @@ -26,8 +12,8 @@ import { handleTokenTransactions } from "@/utils/functions/pretty-exchange-amoun import { handleExchangeType } from "@/utils/functions/exchange-type"; import { IconWrapper, - SkeletonTable, TableHeaderSorting, + TableList, } from "@/components/Shared"; import { DropdownMenu, @@ -49,37 +35,28 @@ export const XYKTokenTransactionsListView: React.FC< on_goldrush_receipt_click, }) => { const { covalentClient } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "block_signed_at", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); useEffect(() => { - setResult(None); (async () => { - let response; + setResult(None); + setErrorMessage(null); try { - response = + const { data, ...error } = await covalentClient.XykService.getTransactionsForTokenAddress( chain_name, dex_name, token_address.trim() ); - setResult(new Some(response.data.items)); - setError({ error: false, error_message: "" }); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items)); } catch (error) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + console.error(error); } })(); }, [token_address, dex_name, chain_name]); @@ -334,91 +311,19 @@ export const XYKTokenTransactionsListView: React.FC< }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => { - return error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => { - return ( - - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - - ); - }) - ) : ( - - - No results. - - - ); - }, - }); - return (
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "block_signed_at", + desc: true, + }, + ]} + />
); }; diff --git a/src/components/Organisms/XYK/XYKWalletPoolListView/XYKWalletPoolListView.tsx b/src/components/Organisms/XYK/XYKWalletPoolListView/XYKWalletPoolListView.tsx index b8d7326a..c0c09e89 100644 --- a/src/components/Organisms/XYK/XYKWalletPoolListView/XYKWalletPoolListView.tsx +++ b/src/components/Organisms/XYK/XYKWalletPoolListView/XYKWalletPoolListView.tsx @@ -11,28 +11,14 @@ import { DropdownMenuLabel, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { type ColumnDef } from "@tanstack/react-table"; + import { TokenAvatar } from "@/components/Atoms"; import { Button } from "@/components/ui/button"; import { IconWrapper, - SkeletonTable, TableHeaderSorting, + TableList, } from "@/components/Shared"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { useGoldRush } from "@/utils/store"; @@ -45,24 +31,16 @@ export const XYKWalletPoolListView: React.FC = ({ wallet_address, }) => { const { covalentClient } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "total_liquidity_quote", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); const [windowWidth, setWindowWidth] = useState(0); useEffect(() => { (async () => { setResult(None); - let response; + setErrorMessage(null); try { - response = + const { data, ...error } = await covalentClient.XykService.getPoolsForWalletAddress( chain_name, wallet_address, @@ -71,27 +49,23 @@ export const XYKWalletPoolListView: React.FC = ({ dexName: dex_name, } ); - setError({ error: false, error_message: "" }); - setResult(new Some(response.data.items)); - } catch (exception) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items)); + } catch (error) { + console.error(error); } })(); }, [chain_name, dex_name, wallet_address]); useEffect(() => { setWindowWidth(window.innerWidth); - const handleResize = () => { setWindowWidth(window.innerWidth); }; - window.addEventListener("resize", handleResize); - return () => { window.removeEventListener("resize", handleResize); }; @@ -415,86 +389,19 @@ export const XYKWalletPoolListView: React.FC = ({ }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns: windowWidth < 700 ? mobile_columns : columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => - error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No results. - - - ), - }); - return (
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={windowWidth < 700 ? mobile_columns : columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "total_liquidity_quote", + desc: true, + }, + ]} + />
); }; diff --git a/src/components/Organisms/XYK/XYKWalletPositionsListView/XYKWalletPositionsListView.tsx b/src/components/Organisms/XYK/XYKWalletPositionsListView/XYKWalletPositionsListView.tsx index 2766697a..fae77cd6 100644 --- a/src/components/Organisms/XYK/XYKWalletPositionsListView/XYKWalletPositionsListView.tsx +++ b/src/components/Organisms/XYK/XYKWalletPositionsListView/XYKWalletPositionsListView.tsx @@ -12,28 +12,13 @@ import { DropdownMenuLabel, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { type ColumnDef } from "@tanstack/react-table"; import { TokenAvatar } from "@/components/Atoms"; import { Button } from "@/components/ui/button"; import { IconWrapper, - SkeletonTable, TableHeaderSorting, + TableList, } from "@/components/Shared"; import { GRK_SIZES } from "@/utils/constants/shared.constants"; import { useGoldRush } from "@/utils/store"; @@ -43,37 +28,28 @@ export const XYKWalletPositionsListView: React.FC< XYKWalletPositionsListViewProps > = ({ chain_name, dex_name, on_pool_click, wallet_address }) => { const { covalentClient } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "total_liquidity_quote", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); useEffect(() => { (async () => { setResult(None); - let response; + setErrorMessage(null); try { - response = + const { data, ...error } = await covalentClient.XykService.getAddressExchangeBalances( chain_name, dex_name, wallet_address ); - setError({ error: false, error_message: "" }); - setResult(new Some(response.data.items)); - } catch (exception) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items)); + } catch (error) { + console.error(error); } })(); }, [chain_name, dex_name, wallet_address]); @@ -247,86 +223,19 @@ export const XYKWalletPositionsListView: React.FC< }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns: columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => - error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No results. - - - ), - }); - return (
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "total_liquidity_quote", + desc: true, + }, + ]} + />
); }; diff --git a/src/components/Organisms/XYK/XYKWalletTransactionsListView/XYKWalletTransactionsListView.tsx b/src/components/Organisms/XYK/XYKWalletTransactionsListView/XYKWalletTransactionsListView.tsx index d064e7c9..4c98ba8e 100644 --- a/src/components/Organisms/XYK/XYKWalletTransactionsListView/XYKWalletTransactionsListView.tsx +++ b/src/components/Organisms/XYK/XYKWalletTransactionsListView/XYKWalletTransactionsListView.tsx @@ -1,23 +1,8 @@ import { type Option, None, Some } from "@/utils/option"; import { type ExchangeTransaction } from "@covalenthq/client-sdk"; import { POOL_TRANSACTION_MAP } from "@/utils/constants/shared.constants"; -import { Fragment, useEffect, useState } from "react"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { useEffect, useState } from "react"; +import { type ColumnDef } from "@tanstack/react-table"; import { timestampParser } from "@/utils/functions"; import { Badge } from "@/components/ui/badge"; import { type XYKWalletTransactionsListViewProps } from "@/utils/types/organisms.types"; @@ -26,8 +11,8 @@ import { handleTokenTransactions } from "@/utils/functions/pretty-exchange-amoun import { handleExchangeType } from "@/utils/functions/exchange-type"; import { IconWrapper, - SkeletonTable, TableHeaderSorting, + TableList, } from "@/components/Shared"; import { DropdownMenu, @@ -49,37 +34,28 @@ export const XYKWalletTransactionsListView: React.FC< on_goldrush_receipt_click, }) => { const { covalentClient } = useGoldRush(); - - const [sorting, setSorting] = useState([ - { - id: "block_signed_at", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); const [maybeResult, setResult] = useState>(None); - const [error, setError] = useState({ error: false, error_message: "" }); + const [errorMessage, setErrorMessage] = useState(null); useEffect(() => { - setResult(None); (async () => { - let response; + setResult(None); + setErrorMessage(null); try { - response = + const { data, ...error } = await covalentClient.XykService.getTransactionsForAccountAddress( chain_name, dex_name, wallet_address.trim() ); - setResult(new Some(response.data.items)); - setError({ error: false, error_message: "" }); + if (error.error) { + setErrorMessage(error.error_message); + throw error; + } + setResult(new Some(data.items)); } catch (error) { - setResult(new Some([])); - setError({ - error: response ? response.error : false, - error_message: response ? response.error_message : "", - }); + console.error(error); } })(); }, [wallet_address, dex_name, chain_name]); @@ -334,96 +310,19 @@ export const XYKWalletTransactionsListView: React.FC< }, ]; - const table = useReactTable({ - data: maybeResult.match({ - None: () => [], - Some: (result) => result, - }), - columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = maybeResult.match({ - None: () => , - Some: () => { - return error.error ? ( - - - {error.error_message} - - - ) : !error.error && table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => { - if ( - !row.original.token_0?.contract_ticker_symbol && - !row.original.token_1?.contract_ticker_symbol - ) - return; - return ( - - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - - ); - }) - ) : ( - - - No results. - - - ); - }, - }); - return (
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "block_signed_at", + desc: true, + }, + ]} + />
); }; diff --git a/src/components/Shared/CardDetail.tsx b/src/components/Shared/CardDetail.tsx new file mode 100644 index 00000000..f7941493 --- /dev/null +++ b/src/components/Shared/CardDetail.tsx @@ -0,0 +1,20 @@ +import { type CardDetailProps } from "@/utils/types/shared.types"; +import { CardContent, CardDescription } from "../ui/card"; + +export const CardDetail: React.FC = ({ + content = null, + heading = null, + subtext = null, + wrapperClassName = "", +}) => { + return ( +
+ {heading} + + + {content}{" "} + {subtext ? {subtext} : <>} + +
+ ); +}; diff --git a/src/components/Shared/TableList.tsx b/src/components/Shared/TableList.tsx new file mode 100644 index 00000000..5fa7b533 --- /dev/null +++ b/src/components/Shared/TableList.tsx @@ -0,0 +1,111 @@ +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { type TableListProps } from "@/utils/types/shared.types"; +import { + type SortingState, + useReactTable, + getCoreRowModel, + getSortedRowModel, + flexRender, +} from "@tanstack/react-table"; +import { useState } from "react"; +import { SkeletonTable } from "./SkeletonTable"; + +export const TableList: (props: TableListProps) => JSX.Element = ({ + columns, + row_selection_state = {}, + errorMessage, + maybeData, + sorting_state = [], +}) => { + const [sorting, setSorting] = useState(sorting_state); + const [rowSelection, setRowSelection] = useState(row_selection_state); + + const table = useReactTable({ + data: maybeData.match({ + None: () => [], + Some: (result) => result, + }), + columns, + onSortingChange: setSorting, + getCoreRowModel: getCoreRowModel(), + getSortedRowModel: getSortedRowModel(), + onRowSelectionChange: setRowSelection, + state: { + sorting, + rowSelection, + }, + }); + + return ( + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ); + })} + + ))} + + + {maybeData.match({ + None: () => , + Some: () => + errorMessage ? ( + + + {errorMessage} + + + ) : table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + No results. + + + ), + })} + +
+ ); +}; diff --git a/src/components/Shared/Transactions.tsx b/src/components/Shared/Transactions.tsx index ab27cfa3..79b33c1c 100644 --- a/src/components/Shared/Transactions.tsx +++ b/src/components/Shared/Transactions.tsx @@ -1,28 +1,10 @@ -import { type Option, None, Some } from "@/utils/option"; import { calculatePrettyBalance, type Transaction, } from "@covalenthq/client-sdk"; -import { useEffect, useState } from "react"; -import { - type ColumnDef, - type SortingState, - flexRender, - getCoreRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { Checkbox } from "@/components/ui/checkbox"; +import { type ColumnDef } from "@tanstack/react-table"; import { timestampParser } from "@/utils/functions"; -import { IconWrapper, SkeletonTable, TableHeaderSorting } from "."; +import { IconWrapper, TableHeaderSorting, TableList } from "."; import { type TransactionsProps } from "@/utils/types/shared.types"; import { Address } from "@/components/Atoms"; import { @@ -41,47 +23,7 @@ export const Transactions: React.FC = ({ errorMessage, maybeResult, }) => { - const [sorting, setSorting] = useState([ - { - id: "block_signed_at", - desc: true, - }, - ]); - const [rowSelection, setRowSelection] = useState({}); - const [filterResult, setFilterResult] = - useState>(None); - - useEffect(() => { - maybeResult.match({ - None: () => setFilterResult(None), - Some: (result) => setFilterResult(new Some(result)), - }); - }, [maybeResult]); - const columns: ColumnDef[] = [ - { - id: "select", - header: ({ table }) => ( - - table.toggleAllPageRowsSelected(!!value) - } - aria-label="Select all" - /> - ), - cell: ({ row }) => ( - row.toggleSelected(!!value)} - aria-label="Select row" - /> - ), - enableSorting: false, - enableHiding: false, - }, { id: "tx_hash", accessorKey: "tx_hash", @@ -295,83 +237,17 @@ export const Transactions: React.FC = ({ }, ]; - const table = useReactTable({ - data: filterResult.match({ - None: () => [], - Some: (result) => result, - }), - columns: columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - onRowSelectionChange: setRowSelection, - state: { - sorting, - rowSelection, - }, - }); - - const body = filterResult.match({ - None: () => , - Some: () => - errorMessage ? ( - - - {errorMessage} - - - ) : table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No results. - - - ), - }); - return ( - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ); - })} - - ))} - - {body} -
+ + columns={columns} + errorMessage={errorMessage} + maybeData={maybeResult} + sorting_state={[ + { + id: "block_signed_at", + desc: true, + }, + ]} + /> ); }; diff --git a/src/components/Shared/index.tsx b/src/components/Shared/index.tsx index 5f7e3faf..a76d835b 100644 --- a/src/components/Shared/index.tsx +++ b/src/components/Shared/index.tsx @@ -1,7 +1,9 @@ export { BalancePriceDelta } from "./BalancePriceDelta"; +export { CardDetail } from "./CardDetail"; export { CopyImage } from "./CopyImage"; export { Heading } from "./Heading"; export { IconWrapper } from "./IconWrapper"; export { SkeletonTable } from "./SkeletonTable"; export { TableHeaderSorting } from "./TableHeaderSorting"; +export { TableList } from "./TableList"; export { Transactions } from "./Transactions"; diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx index 2ef19b79..37fb8a21 100644 --- a/src/components/ui/card.tsx +++ b/src/components/ui/card.tsx @@ -6,7 +6,7 @@ const Card = forwardRef>(
void; +} + export interface GasCardProps { chain_name: Chain; event_type: "erc20" | "nativetokens"; diff --git a/src/utils/types/organisms.types.ts b/src/utils/types/organisms.types.ts index 5ee6cc6a..70a5029c 100644 --- a/src/utils/types/organisms.types.ts +++ b/src/utils/types/organisms.types.ts @@ -1,4 +1,3 @@ -import { type ChainActivityEvent } from "@covalenthq/client-sdk"; import { type BalanceItem, type BlockTransactionWithContractTransfers, @@ -35,11 +34,6 @@ export interface NFTCollectionTokenListViewProps { export interface AddressActivityListViewProps { address: string; - get_all_row_selection?: (newValue: ChainActivityEvent[]) => void; - get_row_selection_state?: (selectionState: { - [key: string]: boolean; - }) => void; - row_selection_state?: { [key: string]: boolean }; } export interface TokenTransferMeta { diff --git a/src/utils/types/shared.types.ts b/src/utils/types/shared.types.ts index 91323464..615ae32b 100644 --- a/src/utils/types/shared.types.ts +++ b/src/utils/types/shared.types.ts @@ -1,12 +1,23 @@ import { type Transaction } from "@covalenthq/client-sdk"; import { type Option } from "@/utils/option"; -import { type Column } from "@tanstack/react-table"; +import { + type ColumnDef, + type SortingState, + type Column, +} from "@tanstack/react-table"; export interface BalancePriceDeltaProps { numerator: number; denominator: number; } +export interface CardDetailProps { + heading?: React.ReactNode; + content?: React.ReactNode; + subtext?: React.ReactNode; + wrapperClassName?: string; +} + export interface CopyImageProps { url: string; } @@ -40,6 +51,14 @@ export interface TableHeaderSortingProps { icon?: boolean; } +export interface TableListProps { + maybeData: Option; + columns: ColumnDef[]; + row_selection_state?: Record; + sorting_state?: SortingState; + errorMessage: string | null; +} + export interface HeadingProps extends React.DetailedHTMLProps< React.HTMLAttributes,