Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/dashboard/src/@/components/blocks/charts/bar-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ export function ThirdwebBarChart<TConfig extends ChartConfig>(
: [0, 0, 0, 0]
: [4, 4, 4, 4]
}
strokeWidth={1}
className="stroke-background"
/>
))}
</BarChart>
Expand Down
58 changes: 58 additions & 0 deletions apps/dashboard/src/@/components/pagination-buttons.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { Meta, StoryObj } from "@storybook/react";
import { useState } from "react";
import { BadgeContainer, mobileViewport } from "../../stories/utils";
import { PaginationButtons } from "./pagination-buttons";

const meta = {
title: "blocks/PaginationButtons",
component: Story,
parameters: {
nextjs: {
appDirectory: true,
},
},
} satisfies Meta<typeof Story>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Desktop: Story = {
args: {},
};

export const Mobile: Story = {
args: {},
parameters: {
viewport: mobileViewport("iphone14"),
},
};

function Story() {
return (
<div className="container flex max-w-[1000px] flex-col gap-8 py-10">
<Variant label="10 Pages" totalPages={10} />
<Variant label="100 Pages" totalPages={100} />
<Variant label="3 Pages" totalPages={2} />
<Variant label="6 Pages" totalPages={6} />
<Variant label="1 Page - nothing rendered" totalPages={1} />
</div>
);
}

function Variant(props: {
label: string;
totalPages: number;
}) {
const [activePage, setActivePage] = useState(1);
return (
<BadgeContainer label={props.label}>
<div className="border bg-card py-5">
<PaginationButtons
activePage={activePage}
onPageClick={setActivePage}
totalPages={props.totalPages}
/>
</div>
</BadgeContainer>
);
}
144 changes: 114 additions & 30 deletions apps/dashboard/src/@/components/pagination-buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,59 @@ import {
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { ArrowUpRightIcon } from "lucide-react";
import { useState } from "react";
import { cn } from "../lib/utils";
import { Button } from "./ui/button";
import { Input } from "./ui/input";

export const PaginationButtons = (props: {
activePage: number;
totalPages: number;
onPageClick: (page: number) => void;
}) => {
const { activePage, totalPages, onPageClick: setPage } = props;
const [inputHasError, setInputHasError] = useState(false);
const [pageNumberInput, setPageNumberInput] = useState("");

if (totalPages === 1) {
return null;
}

function handlePageInputSubmit() {
const page = Number(pageNumberInput);

setInputHasError(false);
if (Number.isInteger(page) && page > 0 && page <= totalPages) {
setPage(page);
setPageNumberInput("");
} else {
setInputHasError(true);
}
}

// just render all the page buttons directly
if (totalPages <= 6) {
const pages = [...Array(totalPages)].map((_, i) => i + 1);
return (
<Pagination>
<PaginationContent>
{pages.map((page) => (
<PaginationItem key={page}>
<PaginationLink
isActive={activePage === page}
onClick={() => {
setPage(page);
}}
>
{page}
</PaginationLink>
</PaginationItem>
))}
</PaginationContent>
</Pagination>
);
}

return (
<Pagination>
Expand All @@ -28,24 +74,28 @@ export const PaginationButtons = (props: {
}}
/>
</PaginationItem>

{/* First page + ... */}
{activePage - 3 > 0 && (
<PaginationItem className="max-sm:hidden">
<PaginationEllipsis />
</PaginationItem>
)}
{activePage - 2 > 0 && (
<PaginationItem className="max-sm:hidden">
<PaginationLink
onClick={() => {
setPage(activePage - 2);
}}
>
{activePage - 2}
</PaginationLink>
</PaginationItem>
<>
<PaginationItem>
<PaginationLink
onClick={() => {
setPage(1);
}}
>
1
</PaginationLink>
</PaginationItem>

<PaginationItem>
<PaginationEllipsis className="max-sm:w-3" />
</PaginationItem>
</>
)}

{activePage - 1 > 0 && (
<PaginationItem>
<PaginationItem className="max-sm:hidden">
<PaginationLink
onClick={() => {
setPage(activePage - 1);
Expand All @@ -55,11 +105,13 @@ export const PaginationButtons = (props: {
</PaginationLink>
</PaginationItem>
)}

<PaginationItem>
<PaginationLink isActive>{activePage}</PaginationLink>
</PaginationItem>

{activePage + 1 <= totalPages && (
<PaginationItem>
<PaginationItem className="max-sm:hidden">
<PaginationLink
onClick={() => {
setPage(activePage + 1);
Expand All @@ -69,22 +121,26 @@ export const PaginationButtons = (props: {
</PaginationLink>
</PaginationItem>
)}
{activePage + 2 <= totalPages && (
<PaginationItem className="max-sm:hidden">
<PaginationLink
onClick={() => {
setPage(activePage + 2);
}}
>
{activePage + 2}
</PaginationLink>
</PaginationItem>
)}

{/* ... + Last page */}
{activePage + 3 <= totalPages && (
<PaginationItem className="max-sm:hidden">
<PaginationEllipsis />
</PaginationItem>
<>
<PaginationItem>
<PaginationEllipsis className="max-sm:w-3" />
</PaginationItem>

<PaginationItem>
<PaginationLink
onClick={() => {
setPage(totalPages);
}}
>
{totalPages}
</PaginationLink>
</PaginationItem>
</>
)}

<PaginationItem>
<PaginationNext
disabled={activePage === totalPages}
Expand All @@ -93,6 +149,34 @@ export const PaginationButtons = (props: {
}}
/>
</PaginationItem>

<div className="relative flex items-center">
<Input
value={pageNumberInput}
onChange={(e) => {
setInputHasError(false);
setPageNumberInput(e.target.value);
}}
type="number"
placeholder="Page"
className={cn(
"w-[60px] bg-transparent [appearance:textfield] max-sm:placeholder:text-sm lg:w-[100px] lg:pr-8 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
inputHasError && "text-red-500",
)}
onKeyDown={(e) => {
if (e.key === "Enter") {
handlePageInputSubmit();
}
}}
/>
<Button
variant="ghost"
className="absolute right-1 h-auto w-auto p-2 max-sm:hidden"
onClick={handlePageInputSubmit}
>
<ArrowUpRightIcon className="size-4" />
</Button>
</div>
</PaginationContent>
</Pagination>
);
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/src/@/components/ui/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ const ChartTooltipContent = React.forwardRef<
<div
ref={ref}
className={cn(
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-popover px-2.5 py-1.5 text-xs shadow-xl",
className,
)}
>
Expand Down
8 changes: 4 additions & 4 deletions apps/dashboard/src/@/components/ui/pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ const PaginationPrevious = ({
<PaginationLink
aria-label="Go to previous page"
size="default"
className={cn("gap-1 pl-2.5", className)}
className={cn("h-10 gap-1 pl-2.5", className)}
{...props}
>
<ChevronLeft className="h-4 w-4" />
<span>Previous</span>
<span className="max-sm:hidden">Previous</span>
</PaginationLink>
);
PaginationPrevious.displayName = "PaginationPrevious";
Expand All @@ -79,10 +79,10 @@ const PaginationNext = ({
<PaginationLink
aria-label="Go to next page"
size="default"
className={cn("gap-1 pr-2.5", className)}
className={cn("h-10 gap-1 pr-2.5", className)}
{...props}
>
<span>Next</span>
<span className="max-sm:hidden">Next</span>
<ChevronRight className="h-4 w-4" />
</PaginationLink>
);
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/src/@3rdweb-sdk/react/cache-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ export const engineKeys = {
[...engineKeys.all, address, "instances"] as const,
backendWallets: (instance: string) =>
[...engineKeys.all, instance, "backendWallets"] as const,
transactions: (instance: string) =>
[...engineKeys.all, instance, "transactions"] as const,
transactions: (instance: string, params: object) =>
[...engineKeys.all, instance, "transactions", params] as const,
permissions: (instance: string) =>
[...engineKeys.all, instance, "permissions"] as const,
accessTokens: (instance: string) =>
Expand Down
30 changes: 26 additions & 4 deletions apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
"use client";

import { apiServerProxy } from "@/actions/proxies";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
keepPreviousData,
useMutation,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import type { ResultItem } from "app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/metrics/components/StatusCodes";
import type { EngineBackendWalletType } from "lib/engine";
import { useState } from "react";
import { useActiveAccount, useActiveWalletChain } from "thirdweb/react";
import invariant from "tiny-invariant";
import type { EngineStatus } from "../../../app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/transactions-table";
import { engineKeys } from "../cache-keys";

export type EngineTier = "STARTER" | "PREMIUM" | "ENTERPRISE";
Expand Down Expand Up @@ -383,13 +389,29 @@ export function useEngineTransactions(params: {
instanceUrl: string;
autoUpdate: boolean;
authToken: string;
queryParams?: {
limit?: number;
page?: number;
status?: EngineStatus;
};
}) {
const { instanceUrl, autoUpdate, authToken } = params;

return useQuery({
queryKey: engineKeys.transactions(instanceUrl),
queryKey: engineKeys.transactions(instanceUrl, params),
queryFn: async () => {
const res = await fetch(`${instanceUrl}transaction/get-all`, {
const url = new URL(`${instanceUrl}transaction/get-all`);
if (params.queryParams) {
for (const key in params.queryParams) {
const value =
params.queryParams[key as keyof typeof params.queryParams];
if (value !== undefined) {
url.searchParams.append(key, value.toString());
}
}
}

const res = await fetch(url, {
method: "GET",
headers: getEngineRequestHeaders(authToken),
});
Expand All @@ -398,8 +420,8 @@ export function useEngineTransactions(params: {

return (json.result as TransactionResponse) || {};
},
enabled: !!instanceUrl,
refetchInterval: autoUpdate ? 4_000 : false,
placeholderData: keepPreviousData,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ export function EcosystemWalletUsersChartCard(props: {
fill={chartConfig[authMethod]?.color}
radius={4}
stackId="a"
strokeWidth={1.5}
className="stroke-muted"
strokeWidth={1}
className="stroke-background"
/>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export const BackendWalletsTable: React.FC<BackendWalletsTableProps> = ({
isPending={isPending}
isFetched={isFetched}
tableScrollableClassName="max-h-[1000px]"
tableContainerClassName="border-x-0 rounded-t-none border-b-0"
onMenuClick={[
{
icon: <PencilIcon className="size-4" />,
Expand Down
Loading
Loading