diff --git a/packages/nextjs/app/api/builders/route.ts b/packages/nextjs/app/api/builders/route.ts new file mode 100644 index 0000000..977f15b --- /dev/null +++ b/packages/nextjs/app/api/builders/route.ts @@ -0,0 +1,19 @@ +import { NextResponse } from "next/server"; +import { readdir } from "fs/promises"; +import path from "path"; + +export async function GET() { + const buildersPath = path.join(process.cwd(), "app/builders"); + + try { + const directories = await readdir(buildersPath, { withFileTypes: true }); + const addresses = directories + .filter(dirent => dirent.isDirectory()) + .map(dirent => dirent.name) + .filter(name => name.startsWith("0x")); + + return NextResponse.json(addresses); + } catch { + return NextResponse.json([], { status: 500 }); + } +} diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index a0a413f..ec2b3f9 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -3,6 +3,7 @@ import Link from "next/link"; import type { NextPage } from "next"; import { BugAntIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import BuildersGrid from "~~/components/batch/BuildersGrid"; const Home: NextPage = () => { return ( @@ -44,6 +45,8 @@ const Home: NextPage = () => { + {/* Builders Grid */} + ); diff --git a/packages/nextjs/components/batch/BuildersGrid.tsx b/packages/nextjs/components/batch/BuildersGrid.tsx new file mode 100644 index 0000000..324d76d --- /dev/null +++ b/packages/nextjs/components/batch/BuildersGrid.tsx @@ -0,0 +1,72 @@ +import Link from "next/link"; +import { useQuery } from "@tanstack/react-query"; +import { Address } from "~~/components/scaffold-eth"; +import { useScaffoldEventHistory } from "~~/hooks/scaffold-eth"; + +const BuildersGrid = () => { + // Get builder profiles from filesystem + const { data: profileBuilders = [], isLoading: profilesLoading } = useQuery({ + queryKey: ["builders-profiles"], + queryFn: async () => { + const response = await fetch("/api/builders"); + if (!response.ok) throw new Error("Failed to fetch builders"); + return response.json(); + }, + }); + + // Get checked-in builders from contract events + const { data: events, isLoading: eventsLoading } = useScaffoldEventHistory({ + contractName: "BatchRegistry", + eventName: "CheckedIn", + fromBlock: 127324219n, + }); + + if (profilesLoading || eventsLoading) { + return ( +
+ +
+ ); + } + + const buildersWithoutProfile = (events ?? []) + .map(event => event.args.builder) + .filter(address => address && !profileBuilders.includes(address)); + + return ( +
+
+ {profileBuilders.map((address, idx) => ( +
+
+
+
+ + View Profile → + +
+
+
+ ))} + {buildersWithoutProfile.map((address, idx) => ( +
+
+
+
+ No Profile +
+
+
+ ))} +
+
+ ); +}; + +export default BuildersGrid;