From fcebfc7507fcc88c2f382d2bebca41e3fdbeb454 Mon Sep 17 00:00:00 2001 From: damnnou Date: Fri, 19 Apr 2024 14:17:01 +0300 Subject: [PATCH 1/3] add: search, farming and my pools filter to pools table --- src/components/common/Table/poolsColumns.tsx | 80 ++++----- src/components/common/Table/poolsTable.tsx | 162 +++++++++---------- src/components/pools/PoolsList/index.tsx | 107 ++++++------ 3 files changed, 153 insertions(+), 196 deletions(-) diff --git a/src/components/common/Table/poolsColumns.tsx b/src/components/common/Table/poolsColumns.tsx index 81a18be..1425d59 100644 --- a/src/components/common/Table/poolsColumns.tsx +++ b/src/components/common/Table/poolsColumns.tsx @@ -1,14 +1,14 @@ -import { ColumnDef } from '@tanstack/react-table'; -import { HeaderItem } from './common'; -import { Address } from 'wagmi'; -import CurrencyLogo from '../CurrencyLogo'; -import { TokenFieldsFragment } from '@/graphql/generated/graphql'; -import { DynamicFeePluginIcon } from '../PluginIcons'; -import { formatUSD } from '@/utils/common/formatUSD'; -import { usePoolPlugins } from '@/hooks/pools/usePoolPlugins'; -import { Skeleton } from '@/components/ui/skeleton'; -import { FarmingPluginIcon } from '../PluginIcons'; -import { useCurrency } from '@/hooks/common/useCurrency'; +import { ColumnDef } from "@tanstack/react-table"; +import { HeaderItem } from "./common"; +import { Address } from "wagmi"; +import CurrencyLogo from "../CurrencyLogo"; +import { TokenFieldsFragment } from "@/graphql/generated/graphql"; +import { DynamicFeePluginIcon } from "../PluginIcons"; +import { formatUSD } from "@/utils/common/formatUSD"; +import { usePoolPlugins } from "@/hooks/pools/usePoolPlugins"; +import { Skeleton } from "@/components/ui/skeleton"; +import { FarmingPluginIcon } from "../PluginIcons"; +import { useCurrency } from "@/hooks/common/useCurrency"; interface Pair { token0: TokenFieldsFragment; @@ -23,6 +23,8 @@ interface Pool { volume24USD: number; maxApr: number; avgApr: number; + isMyPool: boolean; + hasActiveFarming: boolean; } const PoolPair = ({ pair, fee }: Pool) => { @@ -36,11 +38,7 @@ const PoolPair = ({ pair, fee }: Pool) => {
- +
{currencyA && currencyB ? ( @@ -67,76 +65,52 @@ const Plugins = ({ poolId }: { poolId: Address }) => { export const poolsColumns: ColumnDef[] = [ { - accessorKey: 'pair', + accessorKey: "pair", header: () => Pool, cell: ({ row }) => , filterFn: (v, _, value) => - [ - v.original.pair.token0.symbol, - v.original.pair.token1.symbol, - v.original.pair.token0.name, - v.original.pair.token1.name, - ] - .join(' ') + [v.original.pair.token0.symbol, v.original.pair.token1.symbol, v.original.pair.token0.name, v.original.pair.token1.name] + .join(" ") .toLowerCase() .includes(value), }, { - accessorKey: 'plugins', + accessorKey: "plugins", header: () => Plugins, cell: ({ row }) => , + filterFn: (v, _, value: boolean) => v.original.hasActiveFarming === value, }, { - accessorKey: 'tvlUSD', + accessorKey: "tvlUSD", header: ({ column }) => ( - - column.toggleSorting(column.getIsSorted() === 'asc') - } - isAsc={column.getIsSorted() === 'asc'} - > + column.toggleSorting(column.getIsSorted() === "asc")} isAsc={column.getIsSorted() === "asc"}> TVL ), cell: ({ getValue }) => formatUSD.format(getValue() as number), }, { - accessorKey: 'volume24USD', + accessorKey: "volume24USD", header: ({ column }) => ( - - column.toggleSorting(column.getIsSorted() === 'asc') - } - isAsc={column.getIsSorted() === 'asc'} - > + column.toggleSorting(column.getIsSorted() === "asc")} isAsc={column.getIsSorted() === "asc"}> Volume 24H ), cell: ({ getValue }) => formatUSD.format(getValue() as number), }, { - accessorKey: 'maxApr', + accessorKey: "maxApr", header: ({ column }) => ( - - column.toggleSorting(column.getIsSorted() === 'asc') - } - isAsc={column.getIsSorted() === 'asc'} - > + column.toggleSorting(column.getIsSorted() === "asc")} isAsc={column.getIsSorted() === "asc"}> Max. APR ), cell: ({ getValue }) => `${getValue()} %`, }, { - accessorKey: 'avgApr', + accessorKey: "avgApr", header: ({ column }) => ( - - column.toggleSorting(column.getIsSorted() === 'asc') - } - isAsc={column.getIsSorted() === 'asc'} - > + column.toggleSorting(column.getIsSorted() === "asc")} isAsc={column.getIsSorted() === "asc"}> Avg. APR ), diff --git a/src/components/common/Table/poolsTable.tsx b/src/components/common/Table/poolsTable.tsx index f3d0eea..ca18ad1 100644 --- a/src/components/common/Table/poolsTable.tsx +++ b/src/components/common/Table/poolsTable.tsx @@ -1,12 +1,5 @@ -import { Button } from '@/components/ui/button'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/ui/table'; +import { Button } from "@/components/ui/button"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { ColumnDef, ColumnFiltersState, @@ -17,15 +10,17 @@ import { getPaginationRowModel, getSortedRowModel, useReactTable, -} from '@tanstack/react-table'; -import { useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { LoadingState } from './loadingState'; +} from "@tanstack/react-table"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { LoadingState } from "./loadingState"; +import { Input } from "@/components/ui/input"; +import { Search, Tractor } from "lucide-react"; +import { Switch } from "@/components/ui/switch"; interface PoolsTableProps { columns: ColumnDef[]; data: TData[]; - selectedRow?: number; action?: (args?: any) => void; defaultSortingID?: string; link?: string; @@ -37,17 +32,15 @@ interface PoolsTableProps { const PoolsTable = ({ columns, data, - selectedRow, action, link, defaultSortingID, showPagination = true, loading, }: PoolsTableProps) => { - const [sorting, setSorting] = useState( - defaultSortingID ? [{ id: defaultSortingID, desc: true }] : [] - ); + const [sorting, setSorting] = useState(defaultSortingID ? [{ id: defaultSortingID, desc: true }] : []); const [columnFilters, setColumnFilters] = useState([]); + const [isMyPools, setIsMyPools] = useState(false); const navigate = useNavigate(); @@ -55,9 +48,7 @@ const PoolsTable = ({ data, columns, getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: showPagination - ? getPaginationRowModel() - : undefined, + getPaginationRowModel: showPagination ? getPaginationRowModel() : undefined, onSortingChange: setSorting, getSortedRowModel: getSortedRowModel(), onColumnFiltersChange: setColumnFilters, @@ -68,84 +59,101 @@ const PoolsTable = ({ }, }); + const searchID = "pair"; + + const tableRows = isMyPools ? table.getRowModel().rows.filter((row: any) => row.original.isMyPool) : table.getRowModel().rows; + if (loading) return ; return ( <> + {searchID && ( +
+
+ table.getColumn(searchID)?.setFilterValue(event.target.value)} + className="border border-border border-opacity-60 pl-12 h-12 w-64 focus:border-opacity-100 rounded-xl" + /> + +
+
    +
  • + +
  • +
  • + +
  • +
+
+ + { + const column = table.getColumn("plugins"); + if (column?.getFilterValue() === undefined) column?.setFilterValue(true); + else column?.setFilterValue(undefined); + }} + /> +
+
+ )} - + {table.getHeaderGroups().map((headerGroup) => ( - + {headerGroup.headers.map((header) => ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext() - )} + + {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} ))} ))} - {!table.getRowModel().rows?.length ? ( + {!tableRows.length ? ( - + No results. ) : ( - table.getRowModel().rows.map((row: any) => { - const isSelected = - Number(selectedRow) === Number(row.original.id); - + tableRows.map((row: any) => { return ( { if (action) { action(row.original.id); } else if (link) { - navigate( - `/${link}/${row.original.id}` - ); + navigate(`/${link}/${row.original.id}`); } }} > {row.getVisibleCells().map((cell: any) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} + + {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} @@ -156,20 +164,10 @@ const PoolsTable = ({
{showPagination && (
- -
diff --git a/src/components/pools/PoolsList/index.tsx b/src/components/pools/PoolsList/index.tsx index d094a86..4f7ef14 100644 --- a/src/components/pools/PoolsList/index.tsx +++ b/src/components/pools/PoolsList/index.tsx @@ -1,81 +1,66 @@ -import { poolsColumns } from '@/components/common/Table/poolsColumns'; -import { - usePoolsListQuery, - usePoolsVolumeDataQuery, -} from '@/graphql/generated/graphql'; -import { useMemo } from 'react'; -import { Address } from 'viem'; -import { POOL_AVG_APR_API, POOL_MAX_APR_API, fetcher } from '@/constants/api'; -import useSWR from 'swr'; -import PoolsTable from '@/components/common/Table/poolsTable'; +import { poolsColumns } from "@/components/common/Table/poolsColumns"; +import { usePoolsListQuery, usePoolsVolumeDataQuery } from "@/graphql/generated/graphql"; +import { useMemo } from "react"; +import { Address } from "viem"; +import { POOL_AVG_APR_API, POOL_MAX_APR_API, fetcher } from "@/constants/api"; +import useSWR from "swr"; +import PoolsTable from "@/components/common/Table/poolsTable"; +import { usePositions } from "@/hooks/positions/usePositions"; +import { usePoolsStore } from "@/state/poolsStore"; const PoolsList = () => { const { data: pools, loading: isPoolsListLoading } = usePoolsListQuery(); - const { data: poolsVolume, loading: isPoolsVolumeLoading } = - usePoolsVolumeDataQuery(); + const { data: poolsVolume, loading: isPoolsVolumeLoading } = usePoolsVolumeDataQuery(); - const { data: poolsMaxApr, isLoading: isPoolsMaxAprLoading } = useSWR( - POOL_MAX_APR_API, - fetcher - ); - const { data: poolsAvgApr, isLoading: isPoolsAvgAprLoading } = useSWR( - POOL_AVG_APR_API, - fetcher - ); + const { data: poolsMaxApr, isLoading: isPoolsMaxAprLoading } = useSWR(POOL_MAX_APR_API, fetcher); + const { data: poolsAvgApr, isLoading: isPoolsAvgAprLoading } = useSWR(POOL_AVG_APR_API, fetcher); + + const { positions, loading: isPositionsLoading } = usePositions(); - const isLoading = - isPoolsListLoading || - isPoolsVolumeLoading || - isPoolsMaxAprLoading || - isPoolsAvgAprLoading; + const isLoading = isPoolsListLoading || isPoolsVolumeLoading || isPoolsMaxAprLoading || isPoolsAvgAprLoading || isPositionsLoading; + + const { pluginsForPools } = usePoolsStore(); const formattedPools = useMemo(() => { - if ( - !pools?.pools || - !poolsMaxApr || - !poolsAvgApr || - !poolsVolume?.poolDayDatas - ) - return []; + if (!pools?.pools || !poolsMaxApr || !poolsAvgApr || !poolsVolume?.poolDayDatas || !positions) return []; + + return pools.pools.map(({ id, token0, token1, fee, totalValueLockedUSD }) => { + const currentPool = poolsVolume.poolDayDatas.find((currPool) => currPool.pool.id === id); + const lastDate = currentPool ? currentPool.date * 1000 : 0; + const currentDate = new Date().getTime(); + + const timeDifference = currentDate - lastDate; + const msIn24Hours = 24 * 60 * 60 * 1000; - return pools.pools.map( - ({ id, token0, token1, fee, totalValueLockedUSD }) => { - const currentPool = poolsVolume.poolDayDatas.find( - (currPool) => currPool.pool.id === id - ); - const lastDate = currentPool ? currentPool.date * 1000 : 0; - const currentDate = new Date().getTime(); + const openPositions = positions.filter((position) => position.pool.toLowerCase() === id.toLowerCase()); - const timeDifference = currentDate - lastDate; - const msIn24Hours = 24 * 60 * 60 * 1000; + const hasActiveFarming = pluginsForPools[id as Address]?.farmingPlugin; - return { - id: id as Address, - pair: { - token0, - token1, - }, - fee: Number(fee) / 10_000, - tvlUSD: Number(totalValueLockedUSD), - volume24USD: - timeDifference <= msIn24Hours && currentPool - ? currentPool.volumeUSD - : 0, - maxApr: poolsMaxApr[id] ? poolsMaxApr[id].toFixed(2) : 0, - avgApr: poolsAvgApr[id] ? poolsAvgApr[id].toFixed(2) : 0, - }; - } - ); - }, [pools, poolsMaxApr, poolsAvgApr, poolsVolume]); + return { + id: id as Address, + pair: { + token0, + token1, + }, + fee: Number(fee) / 10_000, + tvlUSD: Number(totalValueLockedUSD), + volume24USD: timeDifference <= msIn24Hours && currentPool ? currentPool.volumeUSD : 0, + maxApr: poolsMaxApr[id] ? poolsMaxApr[id].toFixed(2) : 0, + avgApr: poolsAvgApr[id] ? poolsAvgApr[id].toFixed(2) : 0, + isMyPool: openPositions?.length > 0, + hasActiveFarming, + }; + }); + }, [pools, poolsMaxApr, poolsAvgApr, poolsVolume, positions]); return (
From 60b802222f8da24777324fb3a87f637c0ba956ba Mon Sep 17 00:00:00 2001 From: damnnou Date: Sat, 20 Apr 2024 00:26:38 +0300 Subject: [PATCH 2/3] fix: add global filter isMyPools --- src/components/common/Table/poolsTable.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/common/Table/poolsTable.tsx b/src/components/common/Table/poolsTable.tsx index ca18ad1..02c0e4d 100644 --- a/src/components/common/Table/poolsTable.tsx +++ b/src/components/common/Table/poolsTable.tsx @@ -40,7 +40,6 @@ const PoolsTable = ({ }: PoolsTableProps) => { const [sorting, setSorting] = useState(defaultSortingID ? [{ id: defaultSortingID, desc: true }] : []); const [columnFilters, setColumnFilters] = useState([]); - const [isMyPools, setIsMyPools] = useState(false); const navigate = useNavigate(); @@ -57,31 +56,32 @@ const PoolsTable = ({ sorting, columnFilters, }, + globalFilterFn: (row: any, _, value: boolean | undefined) => row.original.isMyPool === value, }); - const searchID = "pair"; + const isMyPools: boolean | undefined = table.getState().globalFilter; - const tableRows = isMyPools ? table.getRowModel().rows.filter((row: any) => row.original.isMyPool) : table.getRowModel().rows; + const searchID = "pair"; if (loading) return ; return ( <> {searchID && ( -
+
table.getColumn(searchID)?.setFilterValue(event.target.value)} - className="border border-border border-opacity-60 pl-12 h-12 w-64 focus:border-opacity-100 rounded-xl" + className="border border-border border-opacity-60 pl-12 h-12 w-80 focus:border-opacity-100 rounded-xl" />
return
-
+
diff --git a/src/components/common/Table/poolsTable.tsx b/src/components/common/Table/poolsTable.tsx index 02c0e4d..adb3b87 100644 --- a/src/components/common/Table/poolsTable.tsx +++ b/src/components/common/Table/poolsTable.tsx @@ -74,15 +74,15 @@ const PoolsTable = ({ placeholder="Search pool" value={(table.getColumn(searchID)?.getFilterValue() as string) ?? ""} onChange={(event) => table.getColumn(searchID)?.setFilterValue(event.target.value)} - className="border border-border border-opacity-60 pl-12 h-12 w-80 focus:border-opacity-100 rounded-xl" + className="border border-border border-opacity-60 pl-12 h-12 max-w-80 md:w-64 lg:w-80 focus:border-opacity-100 rounded-xl" />
-
    +
    -
    +