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 */}
+
+ 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({