From d3fdeb4bf0ded35b5bd6c44da96062ef665ce220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez?= Date: Fri, 16 Feb 2024 11:10:02 +0100 Subject: [PATCH] Admin page with admin data --- packages/nextjs/app/admin/page.tsx | 48 +++++++++++++++++++- packages/nextjs/app/api/auth/siwe/route.tsx | 5 +- packages/nextjs/app/api/grants/all/route.tsx | 22 +++++++++ packages/nextjs/app/page.tsx | 3 -- packages/nextjs/components/SIWE.tsx | 2 +- 5 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 packages/nextjs/app/api/grants/all/route.tsx diff --git a/packages/nextjs/app/admin/page.tsx b/packages/nextjs/app/admin/page.tsx index 70f727c..f353de1 100644 --- a/packages/nextjs/app/admin/page.tsx +++ b/packages/nextjs/app/admin/page.tsx @@ -1,12 +1,56 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useReadLocalStorage } from "usehooks-ts"; +import { useAccount } from "wagmi"; import SIWE from "~~/components/SIWE"; +import { GrantData } from "~~/services/database/schema"; +import { notification } from "~~/utils/scaffold-eth"; + +const AdminPage = () => { + const [grants, setGrants] = useState([]); + const { isConnected } = useAccount(); + const jwt = useReadLocalStorage("jwt"); + + // In use effect, make get request (with JWT) to /api/grants/all + useEffect(() => { + const getGrants = async () => { + try { + const response = await fetch("/api/grants/all", { + headers: { + Authorization: `Bearer ${jwt}`, + }, + }); + const grants: GrantData[] = (await response.json()).data; + setGrants(grants); + } catch (error) { + notification.error("Error getting grants"); + } + }; + + if (jwt) getGrants(); + }, [jwt]); -const Home = () => { return (

Admin page

+

Admin data:

+ {!isConnected || !jwt ? ( +

Connect & authenticate to see admin data

+ ) : ( + <> +

All grants:

+ {grants.map(grant => ( +
+

{grant.title}

+

{grant.description}

+
+ ))} + + )}
); }; -export default Home; +export default AdminPage; diff --git a/packages/nextjs/app/api/auth/siwe/route.tsx b/packages/nextjs/app/api/auth/siwe/route.tsx index ebfd408..a0464e6 100644 --- a/packages/nextjs/app/api/auth/siwe/route.tsx +++ b/packages/nextjs/app/api/auth/siwe/route.tsx @@ -1,3 +1,4 @@ +import { NextResponse } from "next/server"; import jwt from "jsonwebtoken"; import { verifyMessage } from "viem"; import { findUserByAddress } from "~~/services/database/users"; @@ -17,7 +18,5 @@ export async function POST(request: Request) { const token = jwt.sign({ address }, process.env.JWT_SECRET, { expiresIn: "1w" }); - return new Response(JSON.stringify({ token }), { - headers: { "Content-Type": "application/json" }, - }); + return NextResponse.json({ token }); } diff --git a/packages/nextjs/app/api/grants/all/route.tsx b/packages/nextjs/app/api/grants/all/route.tsx new file mode 100644 index 0000000..a3df800 --- /dev/null +++ b/packages/nextjs/app/api/grants/all/route.tsx @@ -0,0 +1,22 @@ +import { NextResponse } from "next/server"; +import jwt from "jsonwebtoken"; +import { getAllGrants } from "~~/services/database/grants"; + +export async function GET(request: Request) { + // ToDo. We probably want to use a middleware for this. + const authHeader = request.headers.get("Authorization"); + if (!authHeader || !authHeader.startsWith("Bearer ")) { + return new Response("Unauthorized", { status: 401 }); + } + + const token = authHeader.split(" ")[1]; + try { + jwt.verify(token, process.env.JWT_SECRET || ""); + } catch (error) { + return new Response("Unauthorized", { status: 401 }); + } + + const grants = await getAllGrants(); + + return NextResponse.json({ data: grants }); +} diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index a03730d..4a3cab9 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -1,7 +1,6 @@ import { CompletedGrants } from "./_components/CompletedGrants"; import { GrantsStats } from "./_components/GrantsStats"; import { HomepageHero } from "./_components/HomepageHero"; -import SIWE from "~~/components/SIWE"; const Home = () => { return ( @@ -9,8 +8,6 @@ const Home = () => { -

SIWE:

- ); }; diff --git a/packages/nextjs/components/SIWE.tsx b/packages/nextjs/components/SIWE.tsx index 192a7b2..cae8006 100644 --- a/packages/nextjs/components/SIWE.tsx +++ b/packages/nextjs/components/SIWE.tsx @@ -5,7 +5,7 @@ import { useLocalStorage } from "usehooks-ts"; import { useAccount, useSignMessage } from "wagmi"; import { notification } from "~~/utils/scaffold-eth"; -// ToDo. Connect wallet tooltip if disabled +// ToDo. "Connect wallet" info tooltip if disabled // ToDo. Nonce? // ToDo. Check if expired? const SIWE = () => {