Skip to content

Commit

Permalink
Merge branch 'gg-22' into PAR-477
Browse files Browse the repository at this point in the history
  • Loading branch information
thelostone-mc authored Oct 10, 2024
2 parents daf0a26 + 0031831 commit eba1f94
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 171 deletions.
121 changes: 121 additions & 0 deletions packages/grant-explorer/src/attestationStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { create } from "zustand";
import { devtools } from "zustand/middleware";
import { CartProject, AttestationFrameProps } from "./features/api/types";
import { persist } from "zustand/middleware";

import { Hex } from "viem";

interface AttestationState {
checkedOutProjectsByTx: Record<Hex, CartProject[]>;
setCheckedOutProjectsByTx: (tx: Hex, projects: CartProject[]) => void;
getCheckedOutProjectsByTx: (tx: Hex) => CartProject[];
cleanCheckedOutProjects: () => void;
getCheckedOutTransactions: () => Hex[];
getFrameProps: (txHashes: Hex[]) => AttestationFrameProps;
}

export const useAttestationStore = create<AttestationState>()(
persist(
devtools((set, get) => ({
checkedOutProjectsByTx: {},
setCheckedOutProjectsByTx: (tx: Hex, projects: CartProject[]) => {
set((oldState) => ({
checkedOutProjectsByTx: {
...oldState.checkedOutProjectsByTx,
[tx]: projects,
},
}));
},
getCheckedOutProjectsByTx: (tx: Hex) => {
return get().checkedOutProjectsByTx[tx] || [];
},
cleanCheckedOutProjects: () => {
set({
checkedOutProjectsByTx: {},
});
},
// Create a function that gets an array of transactionHashes and returns the FrameProps object where projects Array
// contains the top 3 projects based on those checked out transactions max donation amount in usd
// The top round is the round with the most funds allocated in total amount of projects allocated to all transactions in total rounds in all transaction in total chains allocated in these transactions
getCheckedOutTransactions: () => {
return Object.keys(get().checkedOutProjectsByTx) as Hex[];
},
getFrameProps: (txHashes: Hex[]) => {
const allProjects: CartProject[] = [];
const roundsSet = new Set<string>();
const chainsSet = new Set<number>();
const amountByRound: Record<
string,
{
roundId: string;
chainId: number;
totalAmount: number;
}
> = {};

if (txHashes.length === 0) {
return {
selectedBackground: "",
topRound: {
roundId: "",
chainId: 0,
},
projectsFunded: 0,
roundsSupported: 0,
checkedOutChains: 0,
projects: [],
} as AttestationFrameProps;
}

for (const txHash of txHashes) {
const projects = get().getCheckedOutProjectsByTx(txHash);
allProjects.push(...projects);
projects.forEach((project) => {
roundsSet.add(project.roundId);
chainsSet.add(project.chainId);
amountByRound[project.roundId] = amountByRound[project.roundId] || {
roundName: project.roundId,
totalAmount: 0,
};
// TODO CHANGE WITH ACTUAL ROUNDNAME
amountByRound[project.roundId].roundId = project.roundId;
amountByRound[project.roundId].chainId = project.chainId;
amountByRound[project.roundId].totalAmount += Number(
project.amount
);
});
}
const topProjects = allProjects
.sort((a, b) => Number(b.amount) - Number(a.amount))
.slice(0, 3)
.map((project, i) => ({
rank: i + 1,
name: project.projectMetadata.title,
round: project.roundId,
roundId: project.roundId,
image:
project.projectMetadata?.logoImg ??
project.projectMetadata?.bannerImg ??
"",
chainId: project.chainId,
}));
const topRound = Object.values(amountByRound).sort(
(a, b) => b.totalAmount - a.totalAmount
)[0];
return {
selectedBackground: "",
topRound: topRound,
projectsFunded: allProjects.length,
roundsSupported: roundsSet.size,
checkedOutChains: chainsSet.size,
projects: topProjects,
} as AttestationFrameProps;
},
})),
{
name: "attestation-store",
version: 1,
}
)
);
106 changes: 5 additions & 101 deletions packages/grant-explorer/src/checkoutStore.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { create } from "zustand";
import { devtools } from "zustand/middleware";
import {
CartProject,
ProgressStatus,
AttestationFrameProps,
} from "./features/api/types";
import { CartProject, ProgressStatus } from "./features/api/types";
import {
AlloV2,
createEthersTransactionSender,
Expand All @@ -14,6 +10,7 @@ import {
getChainById,
} from "common";
import { useCartStorage } from "./store";
import { useAttestationStore } from "./attestationStore";
import {
getContract,
Hex,
Expand Down Expand Up @@ -70,12 +67,6 @@ interface CheckoutState {
getCheckedOutProjects: () => CartProject[];
checkedOutProjects: CartProject[];
setCheckedOutProjects: (newArray: CartProject[]) => void;
checkedOutProjectsByTx: Record<Hex, CartProject[]>;
setCheckedOutProjectsByTx: (tx: Hex, projects: CartProject[]) => void;
getCheckedOutProjectsByTx: (tx: Hex) => CartProject[];
cleanCheckedOutProjects: () => void;
getCheckedOutTransactions: () => Hex[];
getFrameProps: (txHashes: Hex[]) => AttestationFrameProps;
}

const defaultProgressStatusForAllChains = Object.fromEntries(
Expand Down Expand Up @@ -332,11 +323,9 @@ export const useCheckoutStore = create<CheckoutState>()(
set({
checkedOutProjects: [...get().checkedOutProjects, ...donations],
});
set({
checkedOutProjectsByTx: {
[receipt.transactionHash]: donations,
},
});
useAttestationStore
.getState()
.setCheckedOutProjectsByTx(receipt.transactionHash, donations);
} catch (error) {
let context: Record<string, unknown> = {
chainId,
Expand Down Expand Up @@ -372,91 +361,6 @@ export const useCheckoutStore = create<CheckoutState>()(
checkedOutProjects: newArray,
});
},
checkedOutProjectsByTx: {},
setCheckedOutProjectsByTx: (tx: Hex, projects: CartProject[]) => {
set((oldState) => ({
checkedOutProjectsByTx: {
...oldState.checkedOutProjectsByTx,
[tx]: projects,
},
}));
},
getCheckedOutProjectsByTx: (tx: Hex) => {
return get().checkedOutProjectsByTx[tx] || [];
},
cleanCheckedOutProjects: () => {
set({
checkedOutProjectsByTx: {},
});
},
// Create a function that gets an array of transactionHashes and returns the FrameProps object where projects Array
// contains the top 3 projects based on those checked out transactions max donation amount in usd
// The top round is the round with the most funds allocated in total amount of projects allocated to all transactions in total rounds in all transaction in total chains allocated in these transactions
getCheckedOutTransactions: () => {
return Object.keys(get().checkedOutProjectsByTx) as Hex[];
},
getFrameProps: (txHashes: Hex[]) => {
const allProjects: CartProject[] = [];
const roundsSet = new Set<string>();
const chainsSet = new Set<number>();
const amountByRound: Record<
string,
{
roundName: string;
totalAmount: number;
}
> = {};

if (txHashes.length === 0) {
return {
selectedBackground: "",
topRound: "",
projectsFunded: 0,
roundsSupported: 0,
checkedOutChains: 0,
projects: [],
} as AttestationFrameProps;
}

for (const txHash of txHashes) {
const projects = get().getCheckedOutProjectsByTx(txHash);
allProjects.push(...projects);
projects.forEach((project) => {
roundsSet.add(project.roundId);
chainsSet.add(project.chainId);
amountByRound[project.roundId] = amountByRound[project.roundId] || {
roundName: project.roundId,
totalAmount: 0,
};
// TODO CHANGE WITH ACTUAL ROUNDNAME
amountByRound[project.roundId].roundName = project.roundId;
amountByRound[project.roundId].totalAmount += Number(project.amount);
});
}
const topProjects = allProjects
.sort((a, b) => Number(b.amount) - Number(a.amount))
.slice(0, 3)
.map((project, i) => ({
rank: i,
name: project.projectMetadata.title,
round: project.roundId,
image:
project.projectMetadata?.logoImg ??
project.projectMetadata?.bannerImg ??
"",
}));
const topRoundName = Object.values(amountByRound).sort(
(a, b) => b.totalAmount - a.totalAmount
)[0].roundName;
return {
selectedBackground: "",
topRound: topRoundName,
projectsFunded: allProjects.length,
roundsSupported: roundsSet.size,
checkedOutChains: chainsSet.size,
projects: topProjects,
} as AttestationFrameProps;
},
}))
);

Expand Down
40 changes: 40 additions & 0 deletions packages/grant-explorer/src/context/RoundContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,43 @@ export const useRoundById = (
getRoundByIdError: context.state.getRoundByIdError,
};
};

import { useQuery } from "@tanstack/react-query";

export const useRoundNamesByIds = (rounds: Record<number, string>) => {
const dataLayer = useDataLayer();

return useQuery({
queryKey: ["roundNamesByIds", rounds], // Query key
enabled: !!rounds && Object.keys(rounds).length > 0, // Only fetch if there are rounds
queryFn: async () => {
if (!rounds) {
return {};
}
// Create an empty object to store chainId -> roundId -> roundName
const roundNames: Record<number, Record<string, string>> = {};

await Promise.all(
Object.entries(rounds).map(async ([chainId, roundId]) => {
// If the name is missing, fetch the round data
const fetchedRound = (
await dataLayer.getRoundForExplorer({
roundId,
chainId: Number(chainId),
})
)?.round;

// Store the fetched round name in the result object
if (fetchedRound?.roundMetadata?.name) {
if (!roundNames[Number(chainId)]) {
roundNames[Number(chainId)] = {};
}
roundNames[Number(chainId)][roundId] =
fetchedRound.roundMetadata.name;
}
})
);
return roundNames;
},
});
};
8 changes: 7 additions & 1 deletion packages/grant-explorer/src/features/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,16 @@ export type AttestationProject = {
round: string;
image: string;
amount?: number;
chainId?: number;
roundId?: string;
};

export type AttestationFrameProps = {
topRound: string;
topRound?: {
roundId: string;
chainId: number;
};
topRoundName?: string;
projectsFunded: number;
roundsSupported: number;
checkedOutChains: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ export const HiddenAttestationFrame = ({
checkedOutChains={FrameProps.checkedOutChains}
projectsFunded={FrameProps.projectsFunded}
roundsSupported={FrameProps.roundsSupported}
topRound={FrameProps.topRound}
topRound={FrameProps.topRoundName ?? ""}
address={address}
ensName={name}
/>
Expand All @@ -376,8 +376,12 @@ import { ImageWithLoading } from "../common/components/ImageWithLoading";

export const ImpactMintingSuccess = ({
impactImageCid,
containerSize = "w-[430px] h-[430px]",
imageSize = "w-[400px] h-[400px]",
}: {
impactImageCid?: string;
containerSize?: string;
imageSize?: string;
}) => {
const {
data: image,
Expand All @@ -390,11 +394,14 @@ export const ImpactMintingSuccess = ({
className="flex flex-col items-center text-center w-full relative bg-bottom bg-cover "
style={{ backgroundImage: `url(${bgImage})` }}
>
<div className="flex flex-col items-center justify-center gap-4 px-8 py-6 bg-[#ffffff66] rounded-3xl w-[430px] h-[430px]">
<div
className={`flex flex-col items-center justify-center gap-4 px-8 py-6 bg-[#ffffff66] rounded-3xl ${containerSize}`}
>
<div className="flex flex-col items-center justify-center w-full ">
<ImageWithLoading
src={image?.[0]}
isLoading={isLoading || !image || !impactImageCid || isFetching}
sizeClass={imageSize}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { AttestationFrameProps } from "../../api/types";

export const getRoundsToFetchNames = (props: AttestationFrameProps) => {
if (props.projects.length === 0) {
return {};
}
const roundsToFetchNames: Record<number, string> = {};
props.projects.forEach((project) => {
roundsToFetchNames[project?.chainId ?? 0] = project.roundId ?? "";
});
roundsToFetchNames[props.topRound?.chainId ?? 0] =
props.topRound?.roundId ?? "";

return roundsToFetchNames;
};
Loading

0 comments on commit eba1f94

Please sign in to comment.