Skip to content

Commit

Permalink
Ensure cart data is fresh (#3394)
Browse files Browse the repository at this point in the history
* ensure cart data is fresh

* ensure we're not loading rejected applications

* restore pnpm lock

* update comment

* fix linter

* add comment

* fix comment
  • Loading branch information
boudra authored Apr 29, 2024
1 parent 51b89fc commit bbf1aa7
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 67 deletions.
21 changes: 13 additions & 8 deletions packages/data-layer/src/data-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
SearchResult,
} from "./openapi-search-client/index";
import {
getApplication,
getApprovedApplication,
getApplicationsByProjectIds,
getApplicationsByRoundIdAndProjectIds,
getApplicationsForManager,
Expand Down Expand Up @@ -347,7 +347,7 @@ export class DataLayer {
* Returns a single application as identified by its id, round name and chain name
* @param projectId
*/
async getApplication({
async getApprovedApplication({
roundId,
chainId,
applicationId,
Expand All @@ -362,13 +362,17 @@ export class DataLayer {
applicationId,
};

const response: { application: Application } = await request(
const response: { applications: Application[] } = await request(
this.gsIndexerEndpoint,
getApplication,
getApprovedApplication,
requestVariables,
);

return response.application ?? null;
if (response.applications.length === 0) {
return null;
}

return response.applications[0];
}

async getApplicationsForExplorer({
Expand Down Expand Up @@ -396,7 +400,7 @@ export class DataLayer {
* Returns a list of applications identified by their chainId, roundId, and id.
* @param expandedRefs
*/
async getApplicationsByExpandedRefs(
async getApprovedApplicationsByExpandedRefs(
expandedRefs: Array<ExpandedApplicationRef>,
): Promise<ApplicationSummary[]> {
if (expandedRefs.length === 0) {
Expand All @@ -422,8 +426,9 @@ export class DataLayer {
applications(
first: 100
filter: {
or: [
${filters}
and: [
{ status: { equalTo: APPROVED } },
{ or: [ ${filters} ] }
]
}
) {
Expand Down
12 changes: 10 additions & 2 deletions packages/data-layer/src/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,21 @@ export const getApplicationStatusByRoundIdAndCID = gql`
}
`;

export const getApplication = gql`
export const getApprovedApplication = gql`
query Application(
$chainId: Int!
$applicationId: String!
$roundId: String!
) {
application(chainId: $chainId, id: $applicationId, roundId: $roundId) {
applications(
first: 1
condition: {
status: APPROVED
chainId: $chainId
id: $applicationId
roundId: $roundId
}
) {
id
chainId
roundId
Expand Down
48 changes: 3 additions & 45 deletions packages/grant-explorer/src/checkoutStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ export const useCheckoutStore = create<CheckoutState>()(
checkout: async (
chainsToCheckout: { chainId: ChainId; permitDeadline: number }[],
walletClient: WalletClient,
allo: Allo,
dataLayer: DataLayer
allo: Allo
) => {
const chainIdsToCheckOut = chainsToCheckout.map((chain) => chain.chainId);
get().setChainsToCheckout(
Expand Down Expand Up @@ -238,50 +237,9 @@ export const useCheckoutStore = create<CheckoutState>()(
const groupedEncodedVotes: Record<string, Hex[]> = {};

for (const roundId in groupedDonations) {
const allProjectIds = groupedDonations[roundId].map(
(d) => d.projectRegistryId
);
const response =
await dataLayer.getApplicationsByRoundIdAndProjectIds({
chainId,
roundId,
projectIds: allProjectIds,
});

const roundDonations: {
roundId: string;
chainId: number;
amount: string;
recipient: string;
projectRegistryId: string;
applicationIndex: number;
anchorAddress: string;
}[] = [];

groupedDonations[roundId].map((d) => {
const app = response.find(
(r) => r.projectId === d.projectRegistryId
);

if (!app) {
throw new Error(
`Application not found for projectRegistryId ${d.projectRegistryId} in round ${roundId} on chain ${chainId}`
);
}
roundDonations.push({
roundId: d.roundId,
chainId: d.chainId,
amount: d.amount,
recipient: d.recipient,
projectRegistryId: d.projectRegistryId,
applicationIndex: Number(app.id),
anchorAddress: app.anchorAddress,
});
});

groupedEncodedVotes[roundId] = isV2
? encodedQFAllocation(token, roundDonations)
: encodeQFVotes(token, roundDonations);
? encodedQFAllocation(token, groupedDonations[roundId])
: encodeQFVotes(token, groupedDonations[roundId]);
}

const groupedAmounts: Record<string, bigint> = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const FILTER_OPTIONS: FilterDropdownOption<Filter>[] = [
},
];

function createCartProjectFromApplication(
export function createCartProjectFromApplication(
application: ApplicationSummary
): CartProject {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ export function useApplications(options: ApplicationFetchOptions | null) {
}
case "applications-collection": {
if (options.filter?.type === "expanded-refs") {
const applications = await dataLayer.getApplicationsByExpandedRefs(
options.filter?.refs ?? []
);
const applications =
await dataLayer.getApprovedApplicationsByExpandedRefs(
options.filter?.refs ?? []
);

const v2Applications = applications.filter(
(a) => a.tags?.includes("allo-v2")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export function useApplication(params: Params, dataLayer: DataLayer) {
applicationId: params.applicationId as string,
roundId: params.roundId as string,
};
return (await dataLayer.getApplication(validatedParams)) ?? undefined;
return (
(await dataLayer.getApprovedApplication(validatedParams)) ?? undefined
);
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ChainId, useTokenPrice, VotingToken } from "common";
import React from "react";
import { CHAINS } from "../../api/utils";
import { formatUnits, zeroAddress } from "viem";
import { useAccount, useBalance } from "wagmi";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-unexpected-multiline */
import { ChainId, getTokenPrice, NATIVE, submitPassportLite } from "common";
import { useCartStorage } from "../../../store";
import { useEffect, useMemo, useState } from "react";
Expand Down Expand Up @@ -183,10 +184,8 @@ export function SummaryContainer() {
const currentPermitDeadline =
rounds && rounds.length > 0
? [...rounds]
.sort(
(a, b) => a.roundEndTime.getTime() - b.roundEndTime.getTime()
)[rounds.length - 1]
.roundEndTime.getTime()
.sort((a, b) => a.roundEndTime.getTime() - b.roundEndTime.getTime())
[rounds.length - 1].roundEndTime.getTime()
: 0;

const [emptyInput, setEmptyInput] = useState(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect } from "react";
import { ChainId } from "common";
import { groupProjectsInCart } from "../../api/utils";
import Footer from "common/src/components/Footer";
Expand All @@ -9,11 +9,56 @@ import { Header } from "./Header";
import { useCartStorage } from "../../../store";
import { CartWithProjects } from "./CartWithProjects";
import { SummaryContainer } from "./SummaryContainer";
import { useDataLayer } from "data-layer";
import { createCartProjectFromApplication } from "../../discovery/ExploreProjectsPage";

export default function ViewCart() {
const { projects } = useCartStorage();
const { projects, setCart } = useCartStorage();
const dataLayer = useDataLayer();
const groupedCartProjects = groupProjectsInCart(projects);

// ensure cart data is up to date on mount
useEffect(() => {
const applicationRefs = projects.map((project) => {
return {
chainId: project.chainId,
roundId: project.roundId,
id: project.applicationIndex.toString(),
};
});

// only update cart if fetching applications is successful
dataLayer
.getApprovedApplicationsByExpandedRefs(applicationRefs)
.then((applications) => {
const updatedProjects = applications.flatMap((application) => {
const existingProject = projects.find((project) => {
return applications.some(
(application) =>
application.chainId === project.chainId &&
application.roundId === project.roundId &&
application.roundApplicationId ===
project.applicationIndex.toString()
);
});

const newProject = createCartProjectFromApplication(application);

// update all application data, but preserve the selected amount
return { ...newProject, amount: existingProject?.amount ?? "" };
});

// replace whole cart
setCart(updatedProjects);
})
.catch((error) => {
console.error("error fetching applications in cart", error);
});

// we only want to run this once on mount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const breadCrumbs: BreadcrumbItem[] = [
{
name: "Explorer Home",
Expand Down
8 changes: 8 additions & 0 deletions packages/grant-explorer/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface CartState {
grantApplicationId: string,
amount: string
) => void;
setCart: (projects: CartProject[]) => void;
chainToVotingToken: Record<ChainId, VotingToken>;
getVotingTokenForChain: (chainId: ChainId) => VotingToken;
setVotingTokenForChain: (chainId: ChainId, votingToken: VotingToken) => void;
Expand Down Expand Up @@ -91,6 +92,13 @@ export const useCartStorage = create<CartState>()(
persist(
(set, get) => ({
projects: [],

setCart: (projects: CartProject[]) => {
set({
projects,
});
},

add: (newProject: CartProject) => {
const currentProjects = get().projects;

Expand Down

0 comments on commit bbf1aa7

Please sign in to comment.