diff --git a/packages/nextjs/app/admin/_components/GrantReview.tsx b/packages/nextjs/app/admin/_components/GrantReview.tsx index e446e03..13cab66 100644 --- a/packages/nextjs/app/admin/_components/GrantReview.tsx +++ b/packages/nextjs/app/admin/_components/GrantReview.tsx @@ -1,7 +1,10 @@ import { useSWRConfig } from "swr"; import useSWRMutation from "swr/mutation"; import { useAccount, useSignTypedData } from "wagmi"; -import { GrantData } from "~~/services/database/schema"; +import TelegramIcon from "~~/components/assets/TelegramIcon"; +import TwitterIcon from "~~/components/assets/TwitterIcon"; +import { Address } from "~~/components/scaffold-eth"; +import { GrantData, GrantDataWithBuilder, SocialLinks } from "~~/services/database/schema"; import { EIP_712_DOMAIN, EIP_712_TYPES__REVIEW_GRANT } from "~~/utils/eip712"; import { PROPOSAL_STATUS, ProposalStatusType } from "~~/utils/grants"; import { notification } from "~~/utils/scaffold-eth"; @@ -13,7 +16,36 @@ type ReqBody = { action: ProposalStatusType; }; -export const GrantReview = ({ grant }: { grant: GrantData }) => { +const BuilderSocials = ({ socialLinks }: { socialLinks?: SocialLinks }) => { + if (!socialLinks) return null; + + return ( + <> + {socialLinks?.twitter && ( + + + + )} + {socialLinks?.telegram && ( + + + + )} + + ); +}; + +export const GrantReview = ({ grant }: { grant: GrantDataWithBuilder }) => { const { address } = useAccount(); const { signTypedDataAsync, isLoading: isSigningMessage } = useSignTypedData(); const { trigger: postReviewGrant, isMutating: isPostingNewGrant } = useSWRMutation( @@ -70,25 +102,32 @@ export const GrantReview = ({ grant }: { grant: GrantData }) => { {grant.title} ({grant.id}) +
+ +
+ + +

{grant.description}

-
+
diff --git a/packages/nextjs/app/admin/page.tsx b/packages/nextjs/app/admin/page.tsx index 1e47a32..dc3e7bd 100644 --- a/packages/nextjs/app/admin/page.tsx +++ b/packages/nextjs/app/admin/page.tsx @@ -2,14 +2,14 @@ import { GrantReview } from "./_components/GrantReview"; import useSWR from "swr"; -import { GrantData } from "~~/services/database/schema"; +import { GrantDataWithBuilder } from "~~/services/database/schema"; import { PROPOSAL_STATUS } from "~~/utils/grants"; import { notification } from "~~/utils/scaffold-eth"; // ToDo. "Protect" with address header or PROTECT with signing the read. const AdminPage = () => { // TODO: Move the response type to a shared location - const { data, isLoading } = useSWR<{ data: GrantData[] }>("/api/grants/review", { + const { data, isLoading } = useSWR<{ data: GrantDataWithBuilder[] }>("/api/grants/review", { onError: error => { console.error("Error fetching grants", error); notification.error("Error getting grants data"); diff --git a/packages/nextjs/components/assets/TelegramIcon.tsx b/packages/nextjs/components/assets/TelegramIcon.tsx new file mode 100644 index 0000000..fbb44ac --- /dev/null +++ b/packages/nextjs/components/assets/TelegramIcon.tsx @@ -0,0 +1,13 @@ +import React from "react"; + +const TelegramIcon = (props: React.JSX.IntrinsicAttributes & React.SVGProps) => ( + + Telegram + + +); + +export default TelegramIcon; diff --git a/packages/nextjs/components/assets/TwitterIcon.tsx b/packages/nextjs/components/assets/TwitterIcon.tsx new file mode 100644 index 0000000..5d4c946 --- /dev/null +++ b/packages/nextjs/components/assets/TwitterIcon.tsx @@ -0,0 +1,13 @@ +import React from "react"; + +const TwitterIcon = (props: React.JSX.IntrinsicAttributes & React.SVGProps) => ( + + Twitter + + +); + +export default TwitterIcon; diff --git a/packages/nextjs/services/database/grants.ts b/packages/nextjs/services/database/grants.ts index fffea63..4102253 100644 --- a/packages/nextjs/services/database/grants.ts +++ b/packages/nextjs/services/database/grants.ts @@ -1,5 +1,6 @@ import { getFirestoreConnector } from "./firestoreDB"; -import { GrantData } from "./schema"; +import { BuilderData, GrantData, GrantDataWithBuilder } from "./schema"; +import { findUserByAddress } from "~~/services/database/users"; import { PROPOSAL_STATUS, ProposalStatusType } from "~~/utils/grants"; const firestoreDB = getFirestoreConnector(); @@ -55,11 +56,19 @@ export const getAllGrantsForReview = async () => { const grantsSnapshot = await grantsCollection .where("status", "in", [PROPOSAL_STATUS.PROPOSED, PROPOSAL_STATUS.SUBMITTED]) .get(); - const grants: GrantData[] = []; - grantsSnapshot.forEach(doc => { - grants.push({ id: doc.id, ...doc.data() } as GrantData); + + const grantsPromises = grantsSnapshot.docs.map(async doc => { + const grantData = doc.data() as Omit; + const builderDataResponse = await findUserByAddress(grantData.builder); + + return { + id: doc.id, + ...grantData, + builderData: builderDataResponse.exists ? (builderDataResponse.data as BuilderData) : undefined, + } as GrantDataWithBuilder; }); - return grants; + + return await Promise.all(grantsPromises); } catch (error) { console.error("Error getting all completed grants:", error); throw error; diff --git a/packages/nextjs/services/database/schema.ts b/packages/nextjs/services/database/schema.ts index b4ab8bb..85e01ba 100644 --- a/packages/nextjs/services/database/schema.ts +++ b/packages/nextjs/services/database/schema.ts @@ -1,4 +1,4 @@ -type SocialLinks = { +export type SocialLinks = { twitter?: string; github?: string; discord?: string; @@ -50,3 +50,5 @@ export type GrantData = { // proposed and submited timestamp are imp status: "proposed" | "approved" | "submitted" | "completed" | "rejected"; }; + +export type GrantDataWithBuilder = GrantData & { builderData?: BuilderData };