Skip to content

Commit

Permalink
add pagination and filtering to pool activity table (#52)
Browse files Browse the repository at this point in the history
* add pagination to pool activity table

* fix get transactions filter

* hook up pool activity filters
  • Loading branch information
alecananian authored Jul 16, 2024
1 parent 50c466a commit 5a5d88a
Show file tree
Hide file tree
Showing 11 changed files with 328 additions and 204 deletions.
25 changes: 19 additions & 6 deletions app/api/pools.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { ExecutionResult } from "graphql";

import { uniswapV2PairAbi } from "~/generated";
import { client } from "~/lib/chain.server";
import type { Pool } from "~/lib/pools.server";
import { createPoolFromPair } from "~/lib/pools.server";
import { itemToTroveTokenItem } from "~/lib/tokens.server";
import type { AddressString, Pair } from "~/types";
Expand All @@ -13,19 +12,33 @@ import {
type GetPairTransactionsQuery,
GetPairsDocument,
type GetPairsQuery,
type TransactionType,
execute,
} from "../../.graphclient";
import { fetchTokensCollections } from "./collections.server";
import { fetchMagicUSD } from "./stats.server";
import { fetchTroveTokenMapping } from "./tokens.server";

export const fetchTransactions = async (pool: Pool) => {
export const fetchPoolTransactions = async ({
id,
page = 1,
resultsPerPage = 25,
type,
}: {
id: string;
page?: number;
resultsPerPage?: number;
type?: TransactionType;
}) => {
const result = (await execute(GetPairTransactionsDocument, {
id: pool.id,
pair: id,
first: resultsPerPage,
skip: (page - 1) * resultsPerPage,
...(type ? { where: { type } } : undefined),
})) as ExecutionResult<GetPairTransactionsQuery>;
const { pair } = result.data ?? {};
if (!pair) {
throw new Error(`Pair not found: ${pool.id}`);
throw new Error(`Pair not found: ${id}`);
}

const transactions = pair.transactions;
Expand All @@ -51,9 +64,9 @@ export const fetchTransactions = async (pool: Pool) => {
};

export type PoolTransaction = Awaited<
ReturnType<typeof fetchTransactions>
ReturnType<typeof fetchPoolTransactions>
>[number];
export type PoolTransactionType = PoolTransaction["type"];
export type PoolTransactionType = NonNullable<PoolTransaction["type"]>;
export type PoolTransactionItem = PoolTransaction["items0"][number];

export const createPoolsFromPairs = async (pairs: Pair[]) => {
Expand Down
8 changes: 4 additions & 4 deletions app/api/tokens.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,17 +196,17 @@ export const fetchVaultUserInventory = async ({
export const fetchVaultReserveItems = async ({
id,
page = 1,
itemsPerPage = 25,
resultsPerPage = 25,
}: {
id: string;
page?: number;
itemsPerPage?: number;
resultsPerPage?: number;
}): Promise<TroveToken[]> => {
// Fetch vault reserve items from subgraph
const result = (await execute(GetTokenVaultReserveItemsDocument, {
id,
first: itemsPerPage,
skip: (page - 1) * itemsPerPage,
first: resultsPerPage,
skip: (page - 1) * resultsPerPage,
})) as ExecutionResult<GetTokenVaultReserveItemsQuery>;
const { vaultReserveItems = [] } = result.data ?? {};

Expand Down
8 changes: 6 additions & 2 deletions app/components/item_selection/SelectionPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,11 @@ type Props = ViewOnlyProps | EditableProps;

export const SelectionPopup = ({ token, type, ...props }: Props) => {
const { address } = useAccount();
const { items, isLoading, refetch } = useVaultItems({
const {
results: vaultItems,
isLoading,
refetch,
} = useVaultItems({
id: token.id,
type: type === "vault" ? "reserves" : "inventory",
address,
Expand Down Expand Up @@ -235,7 +239,7 @@ export const SelectionPopup = ({ token, type, ...props }: Props) => {
: "grid-cols-3 md:grid-cols-4 lg:grid-cols-5",
)}
>
{items.map((item) => (
{vaultItems.map((item) => (
<ItemCard
disabled={selectionDisabled}
selected={selectedItems.some(
Expand Down
4 changes: 2 additions & 2 deletions app/components/pools/PoolDepositTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ import { PoolTokenInput } from "./PoolTokenInput";
type Props = {
pool: Pool;
nftBalances: {
nftBalance0: Promise<number> | null;
nftBalance1: Promise<number> | null;
nftBalance0: Promise<number> | undefined;
nftBalance1: Promise<number> | undefined;
};
onSuccess?: () => void;
};
Expand Down
19 changes: 16 additions & 3 deletions app/graphql/pair.queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,28 @@ export const PAIR_FRAGMENT = gql`

export const getPairTransactions = gql`
${TRANSACTION_ITEM_FRAGMENT}
query GetPairTransactions($id: ID!) {
pair(id: $id) {
query GetPairTransactions(
$pair: ID!
$skip: Int = 0
$first: Int = 15
$where: Transaction_filter
$orderBy: Transaction_orderBy = timestamp
$orderDirection: OrderDirection = desc
) {
pair(id: $pair) {
token0 {
id
}
token1 {
id
}
transactions(orderBy: timestamp, orderDirection: desc) {
transactions(
skip: $skip
first: $first
where: $where
orderBy: $orderBy
orderDirection: $orderDirection
) {
id
hash
timestamp
Expand Down
77 changes: 77 additions & 0 deletions app/hooks/usePoolTransactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { useFetcher } from "@remix-run/react";
import { useEffect, useRef, useState } from "react";
import type { PoolTransaction } from "~/api/pools.server";
import type { FetchPoolTransactions } from "~/routes/resources.pools.$id.transactions";
import type { TransactionType } from ".graphclient";

type Props = {
id: string;
type?: TransactionType;
resultsPerPage?: number;
enabled?: boolean;
};

const DEFAULT_STATE = {
page: 1,
isLoading: false,
};

export const usePoolTransactions = ({
id,
type,
resultsPerPage = 25,
enabled = true,
}: Props) => {
const { load, state, data } = useFetcher<FetchPoolTransactions>();
const [{ page, isLoading }, setState] = useState<{
page: number;
isLoading: boolean;
}>(DEFAULT_STATE);
const lastType = useRef<TransactionType | undefined>();
const results = data?.ok ? data.results : [];
const hasPreviousPage = page > 1;
const hasNextPage = results.length === resultsPerPage;

useEffect(() => {
if (enabled) {
if (type !== lastType.current) {
lastType.current = type;
setState(DEFAULT_STATE);
}

const params = new URLSearchParams({
page: page.toString(),
resultsPerPage: resultsPerPage.toString(),
});

if (type) {
params.set("type", type);
}

setState((curr) => ({ ...curr, isLoading: true }));
load(`/resources/pools/${id}/transactions?${params.toString()}`);
setState((curr) => ({ ...curr, isLoading: false }));
} else {
setState(DEFAULT_STATE);
}
}, [enabled, id, type, page, resultsPerPage, load]);

return {
isLoading: isLoading || state === "loading",
results,
page,
resultsPerPage,
hasPreviousPage,
hasNextPage,
goToPreviousPage: () =>
setState((curr) =>
hasPreviousPage ? { ...curr, page: curr.page - 1 } : curr,
),
goToNextPage: () =>
setState((curr) =>
hasNextPage ? { ...curr, page: curr.page + 1 } : curr,
),
refetch: () => setState({ ...DEFAULT_STATE, isLoading: true }),
error: !data?.ok ? data?.error : undefined,
};
};
35 changes: 18 additions & 17 deletions app/hooks/useVaultItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ type Props = {
id: string;
type: "reserves" | "inventory";
address?: string;
itemsPerPage?: number;
resultsPerPage?: number;
enabled?: boolean;
};

const DEFAULT_STATE = {
items: [],
results: [],
page: 1,
hasNextPage: false,
isLoading: false,
Expand All @@ -24,39 +24,40 @@ export const useVaultItems = ({
id,
type,
address,
itemsPerPage = 25,
resultsPerPage = 25,
enabled = true,
}: Props) => {
const { load, state, data } = useFetcher<FetchVaultItems>();
const [{ items, page, hasNextPage, isLoading, error }, setState] = useState<{
items: TroveToken[];
page: number;
hasNextPage: boolean;
isLoading: boolean;
error: string | undefined;
}>(DEFAULT_STATE);
const [{ results, page, hasNextPage, isLoading, error }, setState] =
useState<{
results: TroveToken[];
page: number;
hasNextPage: boolean;
isLoading: boolean;
error: string | undefined;
}>(DEFAULT_STATE);

useEffect(() => {
if (data?.ok) {
setState((curr) => ({
...curr,
items:
curr.page === 1 ? data.results : [...curr.items, ...data.results],
hasNextPage: data.results.length === itemsPerPage,
results:
curr.page === 1 ? data.results : [...curr.results, ...data.results],
hasNextPage: data.results.length === resultsPerPage,
isLoading: false,
error: undefined,
}));
} else if (data?.error) {
setState({ ...DEFAULT_STATE, error: data.error });
}
}, [data, itemsPerPage]);
}, [data, resultsPerPage]);

useEffect(() => {
if (enabled) {
const params = new URLSearchParams({
type,
page: page.toString(),
itemsPerPage: itemsPerPage.toString(),
resultsPerPage: resultsPerPage.toString(),
});

if (type === "inventory" && address) {
Expand All @@ -68,11 +69,11 @@ export const useVaultItems = ({
} else {
setState(DEFAULT_STATE);
}
}, [enabled, id, type, address, page, itemsPerPage, load]);
}, [enabled, id, type, address, page, resultsPerPage, load]);

return {
isLoading: isLoading || state === "loading",
items,
results,
page,
hasNextPage,
loadNextPage: () =>
Expand Down
Loading

0 comments on commit 5a5d88a

Please sign in to comment.