Skip to content

Commit

Permalink
Merge pull request #130 from penumbra-zone/client-suspense-pt1
Browse files Browse the repository at this point in the history
initial `React.Suspense` support in client
  • Loading branch information
ejmg authored Jul 12, 2024
2 parents 50a8843 + 31b5272 commit fc1a080
Show file tree
Hide file tree
Showing 25 changed files with 474 additions and 404 deletions.
46 changes: 38 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-toast": "^1.1.5",
"@tanstack/react-query": "^5.0.5",
"@tanstack/react-query": "^5.49.2",
"@tanstack/react-table": "^8.10.6",
"@types/pg": "^8.11.6",
"axios": "^1.5.1",
Expand All @@ -50,6 +50,7 @@
"@next/eslint-plugin-next": "^14.2.3",
"@pgtyped/cli": "^2.3.0",
"@stylistic/eslint-plugin": "^2.1.0",
"@tanstack/react-query-devtools": "^5.51.1",
"@types/eslint": "^8.56.10",
"@types/node": "^20",
"@types/react": "^18",
Expand Down
58 changes: 17 additions & 41 deletions src/app/block/[ht]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
"use client";

import { type FC } from "react";
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import { BlockData } from "@/lib/validators/search";
import Block from "@/components/Block";
import { Block } from "@/components/Block";
import { getBlock } from "@/components/Block/getBlock";
import { getQueryClient } from "@/lib/utils";

interface PageProps {
params: {
Expand All @@ -15,49 +12,28 @@ interface PageProps {
const Page : FC<PageProps> = ({ params }) => {
const { ht } = params;

const { data: blockData , isError } = useQuery({
queryFn: async () => {
console.log(`Fetching: GET /api/block?q=${ht}`);
const { data } = await axios.get(`/api/block?q=${ht}`);
console.log("Fetching result:", data);
const result = BlockData.safeParse(data);
if (result.success) {
return result.data;
} else {
throw new Error(result.error.message);
}
},
const queryClient = getQueryClient();

const endpoint = "/api/block/";
const queryName = "htQuery";
const errorMessage = "Failed to query block with provided height, please check height or try a different query";

queryClient.prefetchQuery({
queryFn: () => getBlock({ endpoint, ht }),
queryKey: ["htQuery", ht],
retry: false,
meta: {
errorMessage: "Failed to find block event with provided height. Please check height or try a different query.",
errorMessage,
},
});

if (isError) {
return (
<div className="py-5 flex justify-center">
<h1 className="text-4xl font-semibold">No results found.</h1>
</div>
);
}

// TODO: Replace with data table component views once those are fleshed out.
return (
<div className="bg-primary rounded-sm shadow-md">
{blockData ? (
<div className="flex flex-col gap-5 pt-5 items-center">
<h1 className="sm:text-2xl text-lg font-bold">Block Summary</h1>
<div className="sm:w-11/12 w-full">
<Block height={ht} {...blockData}/>
</div>
<div className="flex flex-col gap-5 pt-5 items-center">
<h1 className="sm:text-2xl text-lg font-bold">Block Summary</h1>
<div className="sm:w-11/12 w-full">
<Block {...{endpoint, queryName, ht }}/>
</div>
) : (
<div>
<p className="font-semibold">No block event</p>
<p>To be frank... You shouldn&apos;t be able to see this.</p>
</div>
)}
</div>
</div>
);
};
Expand Down
32 changes: 30 additions & 2 deletions src/app/blocks/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,41 @@
import BlocksTable from "@/components/BlocksTable";
import { BlocksTable } from "@/components/BlocksTable";
import getBlocks from "@/components/BlocksTable/getBlocks";
import { getQueryClient } from "@/lib/utils";
import { HydrationBoundary, dehydrate } from "@tanstack/react-query";

export const dynamic = "force-dynamic";

const Page = () => {
const queryClient = getQueryClient();

const defaultQueryOptions = {
pageIndex: 0,
pageSize: 10,
};

const queryName = "BlocksTable";
const endpoint = "/api/blocks";
const errorMessage = "Failed to query data while trying to generate blocks table, please try reloading the page.";

queryClient.prefetchQuery({
queryFn: () => getBlocks({ endpoint, pageIndex: 0}),
queryKey: [queryName, defaultQueryOptions.pageIndex],
meta: {
errorMessage,
},
});

return (
<div className="bg-primary flex flex-col gap-5 pt-5">
<h1 className="sm:text-2xl font-bold self-center">Recent Blocks</h1>
<BlocksTable className="self-center sm:w-2/3 w-full"/>
<HydrationBoundary state={dehydrate(queryClient)}>
<BlocksTable
className="self-center sm:w-2/3 w-full"
queryName={queryName}
defaultQueryOptions={defaultQueryOptions}
endpoint={endpoint}
errorMessage={errorMessage}/>
</HydrationBoundary>
</div>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;

--muted: 0 0% 96% / 1.0;
--muted: 0 0% 96% / 0.9;
--muted-foreground: 0 0% 45% / 1.0;

--accent: 210 40% 96.1%;
Expand Down Expand Up @@ -60,7 +60,7 @@
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;

--muted: 270 34% 17%;
--muted: 270 34% 17% / 0.9;
--muted-foreground: 0 0% 45% / 1.0;

--accent: 217.2 32.6% 17.5%;
Expand Down
2 changes: 2 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { cn } from "@/lib/utils";
import "@/lib/patch-toJSON-BigInt";
import Navbar from "@/components/Navbar";
import Providers from "@/components/Providers";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { CodeIcon } from "lucide-react";
import Link from "next/link";

Expand Down Expand Up @@ -41,6 +42,7 @@ export default function RootLayout({
</Link>
</div>
</div>
<ReactQueryDevtools initialIsOpen={false} />
</Providers>
</body>
</html>
Expand Down
11 changes: 11 additions & 0 deletions src/app/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Skeleton } from "@/components/ui/skeleton";

export default function Loading() {
return (
<div className="flex flex-wrap items-center justify-center gap-5 w-full h-full">
<Skeleton className="min-w-[300px] sm:min-w-[500px] h-[150px] rounded-lg"/>
<Skeleton className="w-full min-h-[350px] rounded-lg"/>
<Skeleton className="min-w-[200px] min-h-[100px] rounded-lg"/>
</div>
);
}
60 changes: 19 additions & 41 deletions src/app/transaction/[hash]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,40 @@
"use client";

import { type FC } from "react";
import { useQuery } from "@tanstack/react-query";
import { TransactionResult } from "@/lib/validators/search";
import axios from "axios";
import Transaction from "@/components/Transaction";
import { HydrationBoundary, dehydrate } from "@tanstack/react-query";
import { Transaction } from "@/components/Transaction";
import { getTransaction } from "@/components/Transaction/getTransaction";
import { getQueryClient } from "@/lib/utils";

interface PageProps {
params: {
hash: string
}
}

// TODO: this entire page could probably be rendered statically on the server via layout.ts & some minor optimization via tanstack query context.
const Page : FC<PageProps> = ({ params }) => {
const { hash } = params;

const { data: txData , isError } = useQuery({
queryFn: async () => {
console.log(`Fetching: GET /api/transaction?q=${hash}`);
const { data } = await axios.get(`/api/transaction?q=${hash}`);
console.log("Fetched result:", data);
const result = TransactionResult.safeParse(data);
const queryClient = getQueryClient();

if (result.success) {
return result.data;
} else {
throw new Error(result.error.message);
}
},
queryKey: ["txQuery", hash],
retry: false,
const endpoint = "/api/transaction/";
const queryName = "txQuery";
const errorMessage = "Failed to query transaction, please try reloading the page.";

queryClient.prefetchQuery({
queryKey: [queryName, hash],
queryFn: () => getTransaction({ endpoint, hash }),
meta: {
errorMessage: "Failed to find transaction event with provided hash. Please check hash or try a different query.",
errorMessage,
},
});

if (isError) {
return (
<div className="py-5 flex justify-center">
<h1 className="text-4xl font-semibold">No results found.</h1>
</div>
);
}

// TODO: Replace with data table component views once those are fleshed out.
// TODO: add Suspense
return (
<div className="bg-primary rounded-sm shadow-md">
{txData ? (
<div className="flex flex-col items-center gap-5 pt-5">
<h1 className="sm:text-2xl text-lg font-bold">Transaction Event Summary</h1>
<div className="sm:w-11/12 w-full">
<Transaction txData={txData} />
</div>
<div className="bg-primary flex flex-col gap-5 pt-5 items-center ">
<h1 className="font-medium">Transaction Summary</h1>
<HydrationBoundary state={dehydrate(queryClient)}>
<div className="sm:w-11/12 w-full">
<Transaction {...{endpoint, queryName, hash}}/>
</div>
) : <p>No results</p>
}
</HydrationBoundary>
</div>
);
};
Expand Down
36 changes: 33 additions & 3 deletions src/app/transactions/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
import TransactionsTable from "@/components/TransactionsTable";
import { TransactionsTable } from "@/components/TransactionsTable";
import getTransactions from "@/components/TransactionsTable/getTransactions";
import { getQueryClient } from "@/lib/utils";
import { HydrationBoundary, dehydrate } from "@tanstack/react-query";

// TODO: do we want this anymore? what is the story of caching between the client and events.
export const dynamic = "force-dynamic";

const Page = async () => {
const Page = () => {
const queryClient = getQueryClient();

const defaultQueryOptions = {
pageIndex: 0,
pageSize: 10,
};

const endpoint = "/api/transactions";
const queryName = "TransactionsTable";
const errorMessage = "Failed to query data while trying to generate event table, please try reloading the page.";

queryClient.prefetchQuery({
queryFn: () => getTransactions({ endpoint, pageIndex: 0}),
queryKey: [queryName, defaultQueryOptions.pageIndex],
meta: {
errorMessage,
},
});

return (
<div className="bg-primary flex flex-col gap-5 pt-5 items-center">
<h1 className="sm:text-2xl font-bold">Recent Transactions</h1>
<TransactionsTable className="sm:w-11/12 w-full"/>
<HydrationBoundary state={dehydrate(queryClient)}>
<TransactionsTable
className="sm:w-11/12 w-full"
queryName={queryName}
defaultQueryOptions={defaultQueryOptions}
endpoint={endpoint}
errorMessage={errorMessage}/>
</HydrationBoundary>
</div>
);
};
Expand Down
Loading

0 comments on commit fc1a080

Please sign in to comment.