From 5e13165cf7bbb6b38d0de207dbdfc5d28be40c33 Mon Sep 17 00:00:00 2001 From: Ryan Sproule Date: Tue, 14 Apr 2026 13:55:07 -0400 Subject: [PATCH 01/10] editorialize the home page to just valid search index resources --- apps/scan/package.json | 1 + .../(home)/(discover)/_components/columns.tsx | 199 ++++++++++++++++++ .../_components/discover-origins.tsx | 38 ++++ .../app/(app)/(home)/(discover)/loading.tsx | 22 ++ .../src/app/(app)/(home)/(discover)/page.tsx | 78 +++++++ .../app/(app)/(home)/(overview)/loading.tsx | 28 --- .../src/app/(app)/(home)/(overview)/page.tsx | 32 --- .../scan/src/app/(app)/(home)/all/loading.tsx | 28 +++ apps/scan/src/app/(app)/(home)/all/page.tsx | 36 ++++ apps/scan/src/app/(app)/(home)/layout.tsx | 6 +- apps/scan/src/env.ts | 1 + apps/scan/src/lib/discover/origins.ts | 31 +++ apps/scan/src/services/db/bazaar/origins.ts | 1 + apps/scan/src/services/db/bazaar/schema.ts | 1 + .../scan/src/services/db/resources/accepts.ts | 26 ++- pnpm-lock.yaml | 3 + 16 files changed, 463 insertions(+), 68 deletions(-) create mode 100644 apps/scan/src/app/(app)/(home)/(discover)/_components/columns.tsx create mode 100644 apps/scan/src/app/(app)/(home)/(discover)/_components/discover-origins.tsx create mode 100644 apps/scan/src/app/(app)/(home)/(discover)/loading.tsx create mode 100644 apps/scan/src/app/(app)/(home)/(discover)/page.tsx delete mode 100644 apps/scan/src/app/(app)/(home)/(overview)/loading.tsx delete mode 100644 apps/scan/src/app/(app)/(home)/(overview)/page.tsx create mode 100644 apps/scan/src/app/(app)/(home)/all/loading.tsx create mode 100644 apps/scan/src/app/(app)/(home)/all/page.tsx create mode 100644 apps/scan/src/lib/discover/origins.ts diff --git a/apps/scan/package.json b/apps/scan/package.json index 303814667..428e79521 100644 --- a/apps/scan/package.json +++ b/apps/scan/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "@agentcash/discovery": "1.6.0", + "@neondatabase/serverless": "catalog:prisma", "@agentcash/router": "1.2.5", "@ai-sdk/openai": "^2.0.52", "@ai-sdk/react": "^2.0.68", diff --git a/apps/scan/src/app/(app)/(home)/(discover)/_components/columns.tsx b/apps/scan/src/app/(app)/(home)/(discover)/_components/columns.tsx new file mode 100644 index 000000000..ad01522eb --- /dev/null +++ b/apps/scan/src/app/(app)/(home)/(discover)/_components/columns.tsx @@ -0,0 +1,199 @@ +'use client'; + +import { + Activity, + ArrowLeftRight, + Calendar, + DollarSign, + Globe, + Server, + Users, +} from 'lucide-react'; + +import { Skeleton } from '@/components/ui/skeleton'; + +import { + KnownSellerChart, + LoadingKnownSellerChart, +} from '../../(overview)/_components/sellers/known-sellers/chart'; + +import { Origins, OriginsSkeleton } from '@/app/(app)/_components/origins'; + +import { formatCompactAgo } from '@/lib/utils'; +import { formatTokenAmount } from '@/lib/token'; + +import type { ExtendedColumnDef } from '@/components/ui/data-table'; +import type { RouterOutputs } from '@/trpc/client'; +import { HeaderCell } from '@/components/ui/data-table/header-cell'; +import { SellersSortingContext } from '@/app/(app)/_contexts/sorting/sellers/context'; +import { Chains } from '@/app/(app)/_components/chains'; + +type ColumnType = + RouterOutputs['public']['sellers']['bazaar']['list']['items'][number]; + +export const discoverColumns: ExtendedColumnDef[] = [ + { + accessorKey: 'recipients', + header: () => ( + + ), + cell: ({ row }) => { + return ( +
+ +
+ ); + }, + size: 225, + loading: () => , + }, + + { + accessorKey: 'chart', + header: () => ( + + ), + cell: ({ row }) => , + size: 100, + loading: () => , + }, + { + accessorKey: 'tx_count', + header: () => ( + + ), + cell: ({ row }) => ( +
+ {row.original.tx_count.toLocaleString(undefined, { + notation: 'compact', + maximumFractionDigits: 2, + minimumFractionDigits: 0, + })} +
+ ), + size: 100, + loading: () => , + }, + { + accessorKey: 'total_amount', + header: () => ( + + ), + cell: ({ row }) => ( +
+ {formatTokenAmount(BigInt(row.original.total_amount))} +
+ ), + size: 100, + loading: () => , + }, + { + accessorKey: 'unique_buyers', + header: () => ( + + ), + cell: ({ row }) => ( +
+ {row.original.unique_buyers.toLocaleString(undefined, { + notation: 'compact', + maximumFractionDigits: 2, + minimumFractionDigits: 0, + })} +
+ ), + size: 100, + loading: () => , + }, + { + accessorKey: 'latest_block_timestamp', + header: () => ( + + ), + cell: ({ row }) => ( +
+ {row.original.latest_block_timestamp + ? formatCompactAgo(row.original.latest_block_timestamp) + : '–'} +
+ ), + size: 100, + loading: () => , + }, + { + accessorKey: 'chains', + header: () => , + cell: ({ row }) => ( + + ), + size: 100, + loading: () => , + }, + { + accessorKey: 'tryIt', + header: () => , + cell: ({ row }) => { + const origin = row.original.origins[0]?.origin; + if (!origin) return null; + const stripped = origin.replace(/^https?:\/\//, ''); + return ( + e.stopPropagation()} + > + {/* eslint-disable-next-line @next/next/no-img-element */} + Poncho + Try in Poncho + + ); + }, + size: 130, + loading: () => , + }, +]; diff --git a/apps/scan/src/app/(app)/(home)/(discover)/_components/discover-origins.tsx b/apps/scan/src/app/(app)/(home)/(discover)/_components/discover-origins.tsx new file mode 100644 index 000000000..6b22dfebf --- /dev/null +++ b/apps/scan/src/app/(app)/(home)/(discover)/_components/discover-origins.tsx @@ -0,0 +1,38 @@ +'use client'; + +import { DataTable } from '@/components/ui/data-table'; + +import { useSellersSorting } from '@/app/(app)/_contexts/sorting/sellers/hook'; +import { useTimeRangeContext } from '@/app/(app)/_contexts/time-range/hook'; +import { useChain } from '@/app/(app)/_contexts/chain/hook'; + +import { discoverColumns as columns } from './columns'; +import { api } from '@/trpc/client'; + +interface Props { + originUrls: string[]; +} + +export const DiscoverSellersTable: React.FC = ({ originUrls }) => { + const { sorting } = useSellersSorting(); + const { timeframe } = useTimeRangeContext(); + const { chain } = useChain(); + + const [topSellers] = api.public.sellers.bazaar.list.useSuspenseQuery({ + chain, + pagination: { + page_size: 100, + }, + timeframe, + sorting, + originUrls, + }); + + return ; +}; + +export const LoadingDiscoverSellersTable = () => { + return ( + + ); +}; diff --git a/apps/scan/src/app/(app)/(home)/(discover)/loading.tsx b/apps/scan/src/app/(app)/(home)/(discover)/loading.tsx new file mode 100644 index 000000000..39b7bd201 --- /dev/null +++ b/apps/scan/src/app/(app)/(home)/(discover)/loading.tsx @@ -0,0 +1,22 @@ +import { Body, Section } from '@/app/_components/layout/page-utils'; + +import { HomeHeading } from '../(overview)/_components/heading'; +import { LoadingOverallStats } from '../(overview)/_components/stats'; +import { LoadingDiscoverSellersTable } from './_components/discover-origins'; + +export default function LoadingDiscover() { + return ( +
+ + + +
+ +
+ +
+ ); +} diff --git a/apps/scan/src/app/(app)/(home)/(discover)/page.tsx b/apps/scan/src/app/(app)/(home)/(discover)/page.tsx new file mode 100644 index 000000000..e3c19b5e9 --- /dev/null +++ b/apps/scan/src/app/(app)/(home)/(discover)/page.tsx @@ -0,0 +1,78 @@ +import { Suspense } from 'react'; + +import { ErrorBoundary } from 'react-error-boundary'; + +import { Body, Section } from '@/app/_components/layout/page-utils'; + +import { HomeHeading } from '../(overview)/_components/heading'; +import { OverallStats } from '../(overview)/_components/stats'; + +import { api, HydrateClient } from '@/trpc/server'; + +import { getDiscoverOrigins } from '@/lib/discover/origins'; +import { getChainForPage } from '@/app/(app)/_lib/chain/page'; + +import { + DiscoverSellersTable, + LoadingDiscoverSellersTable, +} from './_components/discover-origins'; + +import { defaultSellersSorting } from '@/app/(app)/_contexts/sorting/sellers/default'; +import { SellersSortingProvider } from '@/app/(app)/_contexts/sorting/sellers/provider'; + +import { TimeRangeProvider } from '@/app/(app)/_contexts/time-range/provider'; +import { RangeSelector } from '@/app/(app)/_contexts/time-range/component'; + +import { ActivityTimeframe } from '@/types/timeframes'; + +export default async function DiscoverPage({ + searchParams, +}: { + searchParams: Promise>; +}) { + const chain = await getChainForPage(await searchParams); + const originUrls = await getDiscoverOrigins(); + + void api.public.sellers.bazaar.list.prefetch({ + pagination: { + page_size: 100, + }, + timeframe: ActivityTimeframe.OneDay, + sorting: defaultSellersSorting, + originUrls, + }); + + return ( +
+ + + + + + +
+ +
+ } + > + There was an error loading the discover data

+ } + > + }> + + +
+ + + + + + + ); +} diff --git a/apps/scan/src/app/(app)/(home)/(overview)/loading.tsx b/apps/scan/src/app/(app)/(home)/(overview)/loading.tsx deleted file mode 100644 index d5d242afc..000000000 --- a/apps/scan/src/app/(app)/(home)/(overview)/loading.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Body } from '../../../_components/layout/page-utils'; - -import { HomeHeading } from './_components/heading'; -import { LoadingTopServers } from './_components/sellers/known-sellers'; -import { LoadingLatestTransactions } from './_components/latest-transactions'; -import { LoadingTopFacilitators } from './_components/top-facilitators'; -import { LoadingOverallStats } from './_components/stats'; -import { LoadingAllSellers } from './_components/sellers/all-sellers'; -import { LoadingAllBuyers } from './_components/buyers'; -import { LoadingTopAgents } from './_components/top-agents'; - -export default function LoadingOverview() { - const pageSize = 10; - return ( -
- - - - - - - - - - -
- ); -} diff --git a/apps/scan/src/app/(app)/(home)/(overview)/page.tsx b/apps/scan/src/app/(app)/(home)/(overview)/page.tsx deleted file mode 100644 index 04dc80b0b..000000000 --- a/apps/scan/src/app/(app)/(home)/(overview)/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Body } from '../../../_components/layout/page-utils'; - -import { HomeHeading } from './_components/heading'; -import { OverallStats } from './_components/stats'; -import { TopServers } from './_components/sellers/known-sellers'; -import { TopFacilitators } from './_components/top-facilitators'; -import { LatestTransactions } from './_components/latest-transactions'; -import { AllSellers } from './_components/sellers/all-sellers'; -import { AllBuyers } from './_components/buyers'; -import { getChainForPage } from '@/app/(app)/_lib/chain/page'; -import { TopAgents } from './_components/top-agents'; -import { AgentCashAnnouncementBanner } from '../_components/v2-announcement-banner'; - -export default async function Home({ searchParams }: PageProps<'/'>) { - const chain = await getChainForPage(await searchParams); - - return ( -
- - - - - - - - - - - -
- ); -} diff --git a/apps/scan/src/app/(app)/(home)/all/loading.tsx b/apps/scan/src/app/(app)/(home)/all/loading.tsx new file mode 100644 index 000000000..c8077d134 --- /dev/null +++ b/apps/scan/src/app/(app)/(home)/all/loading.tsx @@ -0,0 +1,28 @@ +import { Body } from '../../../_components/layout/page-utils'; + +import { HomeHeading } from '../(overview)/_components/heading'; +import { LoadingTopServers } from '../(overview)/_components/sellers/known-sellers'; +import { LoadingLatestTransactions } from '../(overview)/_components/latest-transactions'; +import { LoadingTopFacilitators } from '../(overview)/_components/top-facilitators'; +import { LoadingOverallStats } from '../(overview)/_components/stats'; +import { LoadingAllSellers } from '../(overview)/_components/sellers/all-sellers'; +import { LoadingAllBuyers } from '../(overview)/_components/buyers'; +import { LoadingTopAgents } from '../(overview)/_components/top-agents'; + +export default function LoadingAll() { + const pageSize = 10; + return ( +
+ + + + + + + + + + +
+ ); +} diff --git a/apps/scan/src/app/(app)/(home)/all/page.tsx b/apps/scan/src/app/(app)/(home)/all/page.tsx new file mode 100644 index 000000000..c80ebc6ca --- /dev/null +++ b/apps/scan/src/app/(app)/(home)/all/page.tsx @@ -0,0 +1,36 @@ +import { Body } from '../../../_components/layout/page-utils'; + +import { HomeHeading } from '../(overview)/_components/heading'; +import { OverallStats } from '../(overview)/_components/stats'; +import { TopServers } from '../(overview)/_components/sellers/known-sellers'; +import { TopFacilitators } from '../(overview)/_components/top-facilitators'; +import { LatestTransactions } from '../(overview)/_components/latest-transactions'; +import { AllSellers } from '../(overview)/_components/sellers/all-sellers'; +import { AllBuyers } from '../(overview)/_components/buyers'; +import { getChainForPage } from '@/app/(app)/_lib/chain/page'; +import { TopAgents } from '../(overview)/_components/top-agents'; +import { AgentCashAnnouncementBanner } from '../_components/v2-announcement-banner'; + +export default async function AllPage({ + searchParams, +}: { + searchParams: Promise>; +}) { + const chain = await getChainForPage(await searchParams); + + return ( +
+ + + + + + + + + + + +
+ ); +} diff --git a/apps/scan/src/app/(app)/(home)/layout.tsx b/apps/scan/src/app/(app)/(home)/layout.tsx index 43a24b856..23081163e 100644 --- a/apps/scan/src/app/(app)/(home)/layout.tsx +++ b/apps/scan/src/app/(app)/(home)/layout.tsx @@ -11,9 +11,13 @@ export default function HomeLayout({