diff --git a/packages/builder/src/__tests__/reducers/projects.test.ts b/packages/builder/src/__tests__/reducers/projects.test.ts index 8698d6960f..840fb88a6f 100644 --- a/packages/builder/src/__tests__/reducers/projects.test.ts +++ b/packages/builder/src/__tests__/reducers/projects.test.ts @@ -1,10 +1,10 @@ import "@testing-library/jest-dom"; +import { ApplicationStatus, RoundVisibilityType } from "data-layer"; import { - AppStatus, - projectsReducer, ProjectsState, Status, initialState as initialProjectsState, + projectsReducer, } from "../../reducers/projects"; import { addressFrom } from "../../utils/test_utils"; @@ -21,18 +21,64 @@ describe("projects reducer", () => { applications: { "1": [ { - roundID: addressFrom(1), - status: "PENDING" as AppStatus, - inReview: false, + id: "1", chainId: 1, + roundId: addressFrom(1), + status: "PENDING" as ApplicationStatus, + metadataCid: "0x1", + metadata: {}, + inReview: false, + round: { + applicationsStartTime: "0", + applicationsEndTime: "0", + donationsStartTime: "0", + donationsEndTime: "0", + roundMetadata: { + name: "Round 1", + roundType: "public" as RoundVisibilityType, + eligibility: { + description: "Eligibility description", + requirements: [{ requirement: "Requirement 1" }], + }, + programContractAddress: "0x1", + support: { + info: "https://support.com", + type: "WEBSITE", + }, + }, + name: "Round 1", + }, }, ], "2": [ { - roundID: addressFrom(2), - status: "PENDING" as AppStatus, - inReview: false, + id: "1", chainId: 1, + roundId: addressFrom(2), + status: "PENDING" as ApplicationStatus, + metadataCid: "0x1", + metadata: {}, + inReview: false, + round: { + applicationsStartTime: "0", + applicationsEndTime: "0", + donationsStartTime: "0", + donationsEndTime: "0", + roundMetadata: { + name: "Round 2", + roundType: "public" as RoundVisibilityType, + eligibility: { + description: "Eligibility description", + requirements: [{ requirement: "Requirement 1" }], + }, + programContractAddress: "0x1", + support: { + info: "https://support.com", + type: "WEBSITE", + }, + }, + name: "Round 2", + }, }, ], }, @@ -46,8 +92,8 @@ describe("projects reducer", () => { expect(newState.applications).toEqual({ "1": [ { - roundID: addressFrom(1), - status: "PENDING", + roundId: addressFrom(1), + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, @@ -61,8 +107,8 @@ describe("projects reducer", () => { applications: { "1": [ { - roundID: addressFrom(1), - status: "PENDING" as AppStatus, + roundId: addressFrom(1), + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, @@ -75,8 +121,8 @@ describe("projects reducer", () => { projectID: "2", applications: [ { - roundID: addressFrom(2), - status: "APPROVED", + roundId: addressFrom(2), + status: "APPROVED" as ApplicationStatus, inReview: false, chainId: 1, }, @@ -86,16 +132,16 @@ describe("projects reducer", () => { expect(newState.applications).toEqual({ "1": [ { - roundID: addressFrom(1), - status: "PENDING", + roundId: addressFrom(1), + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, ], "2": [ { - roundID: addressFrom(2), - status: "APPROVED", + roundId: addressFrom(2), + status: "APPROVED" as ApplicationStatus, inReview: false, chainId: 1, }, @@ -119,42 +165,42 @@ describe("projects reducer", () => { applications: { "1": [ { - roundID: "0x1", - status: "PENDING" as AppStatus, + roundId: "0x1", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, ], "2": [ { - roundID: "0x1", - status: "PENDING" as AppStatus, + roundId: "0x1", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, { - roundID: "0x2", - status: "PENDING" as AppStatus, + roundId: "0x2", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, { - roundID: "0x3", - status: "PENDING" as AppStatus, + roundId: "0x3", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, { - roundID: "0x4", - status: "PENDING" as AppStatus, + roundId: "0x4", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, ], "3": [ { - roundID: "0x3", - status: "PENDING" as AppStatus, + roundId: "0x3", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, @@ -165,49 +211,49 @@ describe("projects reducer", () => { const newState: ProjectsState = projectsReducer(initialState, { type: "PROJECT_APPLICATION_UPDATED", projectID: "2", - roundID: "0x3", + roundId: "0x3", status: "APPROVED", }); expect(newState.applications).toEqual({ "1": [ { - roundID: "0x1", - status: "PENDING" as AppStatus, + roundId: "0x1", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, ], "2": [ { - roundID: "0x1", - status: "PENDING" as AppStatus, + roundId: "0x1", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, { - roundID: "0x2", - status: "PENDING" as AppStatus, + roundId: "0x2", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, { - roundID: "0x3", - status: "APPROVED" as AppStatus, + roundId: "0x3", + status: "APPROVED" as ApplicationStatus, inReview: false, chainId: 1, }, { - roundID: "0x4", - status: "PENDING" as AppStatus, + roundId: "0x4", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, ], "3": [ { - roundID: "0x3", - status: "PENDING" as AppStatus, + roundId: "0x3", + status: "PENDING" as ApplicationStatus, inReview: false, chainId: 1, }, diff --git a/packages/builder/src/actions/projects.ts b/packages/builder/src/actions/projects.ts index 828c8ac0fa..376f4ebd60 100644 --- a/packages/builder/src/actions/projects.ts +++ b/packages/builder/src/actions/projects.ts @@ -1,22 +1,23 @@ import { datadogRum } from "@datadog/browser-rum"; import { Client as AlloClient } from "allo-indexer-client"; -import { - ChainId, - ROUND_PAYOUT_MERKLE, - RoundPayoutType, - convertStatusToText, -} from "common"; +import { ChainId, ROUND_PAYOUT_MERKLE, RoundPayoutType } from "common"; import { getConfig } from "common/src/config"; -import { DataLayer, ProjectEventsMap } from "data-layer"; +import { + ApplicationStatus, + DataLayer, + ProjectApplication, + ProjectEventsMap, +} from "data-layer"; import { utils } from "ethers"; import { Dispatch } from "redux"; import { addressesByChainID } from "../contracts/deployments"; import { global } from "../global"; import { RootState } from "../reducers"; -import { AppStatus, Application, ProjectStats } from "../reducers/projects"; +import { ProjectStats } from "../reducers/projects"; import { getEnabledChainsAndProviders } from "../utils/chains"; import { graphqlFetch } from "../utils/graphql"; import generateUniqueRoundApplicationID from "../utils/roundApplication"; +import { getV1HashedProjectId } from "../utils/utils"; import { fetchGrantData } from "./grantsMetadata"; import { addAlert } from "./ui"; @@ -25,7 +26,7 @@ export const PROJECTS_LOADING = "PROJECTS_LOADING"; export type SubgraphApplication = { round: { id: string }; - status: AppStatus; + status: ApplicationStatus; inReview: boolean; chainId: ChainId; metaPtr?: { @@ -74,7 +75,7 @@ export const PROJECT_APPLICATIONS_LOADED = "PROJECT_APPLICATIONS_LOADED"; interface ProjectApplicationsLoadedAction { type: typeof PROJECT_APPLICATIONS_LOADED; projectID: string; - applications: Application[]; + applications: ProjectApplication[]; } export const PROJECT_APPLICATION_UPDATED = "PROJECT_APPLICATION_UPDATED"; @@ -83,7 +84,7 @@ interface ProjectApplicationUpdatedAction { type: typeof PROJECT_APPLICATION_UPDATED; projectID: string; roundID: string; - status: AppStatus; + status: ApplicationStatus; } export const PROJECT_APPLICATIONS_ERROR = "PROJECT_APPLICATIONS_ERROR"; @@ -333,102 +334,64 @@ export const fetchProjectApplicationInRound = async ( * This loads project applications for a given project and network and dispatches the * appropriate actions to the store. * - * @param projectID - * @param projectChainId + * @param projectId + * @param dataLayer * * @returns All applications for a given project */ export const fetchProjectApplications = - (projectID: string, projectChainId: ChainId) => + (projectId: string, chainId: ChainId, dataLayer: DataLayer) => async (dispatch: Dispatch) => { + const config = getConfig(); + dispatch({ type: PROJECT_APPLICATIONS_LOADING, - projectID, + projectID: projectId, }); - const { web3Provider } = global; - - if (!web3Provider?.chains) { - return; - } + try { + const { web3Provider } = global; + if (!web3Provider?.chains) { + return; + } - const apps = await Promise.all( - web3Provider.chains.map(async (chain: { id: number }) => { - try { - const addresses = addressesByChainID(projectChainId); - const projectApplicationID = generateUniqueRoundApplicationID( - projectChainId, - projectID, - addresses.projectRegistry! - ); - - const response: any = await graphqlFetch( - `query roundApplications($projectApplicationID: String) { - roundApplications(where: { project: $projectApplicationID }) { - status - round { - id - } - inReview - metaPtr { - pointer - protocol - } - } - } - `, - chain.id, - { - projectApplicationID, - } - ); + const id = + config.allo.version === "allo-v1" + ? getV1HashedProjectId( + `${chainId}:${ + addressesByChainID(chainId).projectRegistry + }:${projectId}` + ) + : projectId; + + const chainIds = web3Provider.chains.map((chain) => chain.id); + const applications = await dataLayer.getApplicationsByProjectId({ + projectId: id, + chainIds, + }); - if (response.errors) { - throw response.errors; - } + applications?.forEach(async (application, index) => { + const programName = await dataLayer.getProgramName({ + projectId: application.round.roundMetadata.programContractAddress, + }); - const applications: Application[] = - response.data.roundApplications.map( - (application: SubgraphApplication) => ({ - status: convertStatusToText(application.status), - roundID: application.round.id, - inReview: application.inReview, - chainId: chain.id, - metaPtr: application.metaPtr, - }) - ); - - if (applications.length === 0) { - return []; - } + applications[index].round.name = programName || ""; + }); - dispatch({ - type: PROJECT_APPLICATIONS_LOADED, - projectID, - applications, - }); - - return applications; - } catch (error: any) { - console.error( - "failed fetchProjectApplications for", - "Project Id", - projectID, - "in Chain Id", - chain.id, - error - ); - datadogRum.addError(error, { projectID }); - - return []; - } - }) - ); - dispatch({ - type: PROJECT_APPLICATIONS_LOADED, - projectID, - applications: apps.flat(), - }); + dispatch({ + type: PROJECT_APPLICATIONS_LOADED, + projectID: projectId, + applications, + }); + } catch (error: any) { + console.error( + "failed fetchProjectApplications for", + "Project Id", + projectId, + error + ); + datadogRum.addError(error, { projectId }); + } }; /** diff --git a/packages/builder/src/actions/roundApplication.ts b/packages/builder/src/actions/roundApplication.ts index a36b37b926..0d8182c84d 100644 --- a/packages/builder/src/actions/roundApplication.ts +++ b/packages/builder/src/actions/roundApplication.ts @@ -4,18 +4,17 @@ import { ChainId, isJestRunning } from "common"; import { ethers } from "ethers"; import { Dispatch } from "redux"; import { getConfig } from "common/src/config"; +import { RoundApplicationAnswers } from "data-layer/dist/roundApplication.types"; import RoundABI from "../contracts/abis/RoundImplementation.json"; import { global } from "../global"; import { RootState } from "../reducers"; import { Status } from "../reducers/roundApplication"; import PinataClient from "../services/pinata"; import { Project, RoundApplication, SignedRoundApplication } from "../types"; -import { RoundApplicationAnswers } from "../types/roundApplication"; import { objectToDeterministicJSON } from "../utils/deterministicJSON"; import generateUniqueRoundApplicationID from "../utils/roundApplication"; import RoundApplicationBuilder from "../utils/RoundApplicationBuilder"; import { getProjectURIComponents, metadataToProject } from "../utils/utils"; -import { fetchProjectApplications } from "./projects"; import { graphqlFetch } from "../utils/graphql"; const LitJsSdk = isJestRunning() ? null : require("gitcoin-lit-js-sdk"); @@ -179,7 +178,7 @@ export const submitApplication = const projectQuestion = roundApplicationMetadata.applicationSchema.questions.find( - (q) => q.type === "project" + (q: { type: string }) => q.type === "project" ); if (!projectQuestion) { @@ -333,9 +332,10 @@ export const submitApplication = roundAddress, projectId: projectID, }); - dispatch( - fetchProjectApplications(projectID, Number(projectChainId)) - ); + // TODO-FIX + // dispatch( + // fetchProjectApplications(projectID, Number(projectChainId)) + // ); } catch (e: any) { dispatchAndLogApplicationError( dispatch, diff --git a/packages/builder/src/actions/rounds.ts b/packages/builder/src/actions/rounds.ts index ccb5a93cef..d0c0bdd65e 100644 --- a/packages/builder/src/actions/rounds.ts +++ b/packages/builder/src/actions/rounds.ts @@ -1,19 +1,12 @@ -import { Dispatch } from "redux"; -// import { RootState } from "../reducers"; import { datadogLogs } from "@datadog/browser-logs"; import { datadogRum } from "@datadog/browser-rum"; -import { getConfig } from "common/src/config"; -import { BigNumber, ethers } from "ethers"; -import ProgramABI from "../contracts/abis/ProgramImplementation.json"; -import RoundABI from "../contracts/abis/RoundImplementation.json"; -import { RootState } from "../reducers"; +import { DataLayer } from "data-layer"; +import { ethers } from "ethers"; +import { Dispatch } from "redux"; import { PayoutStrategy, Status } from "../reducers/rounds"; -import PinataClient from "../services/pinata"; -import { MetaPtr, ProgramMetadata, Round, RoundMetadata } from "../types"; -import { RoundApplicationMetadata } from "../types/roundApplication"; +import { Round } from "../types"; import { graphqlFetch } from "../utils/graphql"; import { parseRoundApplicationMetadata } from "../utils/roundApplication"; -import { getProviderByChainId } from "../utils/utils"; export const ROUNDS_LOADING_ROUND = "ROUNDS_LOADING_ROUND"; interface RoundsLoadingRoundAction { @@ -65,265 +58,40 @@ const loadingError = (address: string, error: string): RoundsActions => ({ export const unloadRounds = () => roundsUnloaded(); -const isTooBig = (bigNumber: BigNumber) => - bigNumber.eq(ethers.constants.MaxUint256); - export const loadRound = - (address: string, roundChainId?: number) => - async (dispatch: Dispatch, getState: () => RootState) => { + (roundId: string, dataLayer: DataLayer, chainId: number) => + async (dispatch: Dispatch) => { try { // address validation - ethers.utils.getAddress(address); + ethers.utils.getAddress(roundId); } catch (e) { datadogRum.addError(e); - datadogLogs.logger.warn(`invalid address or address checksum ${address}`); - dispatch(loadingError(address, "invalid address or address checksum")); + datadogLogs.logger.warn(`invalid address or address checksum ${roundId}`); + dispatch(loadingError(roundId, "invalid address or address checksum")); console.error(e); return; } - const state = getState(); - const { chainID: stateChainID } = state.web3; - const chainId = roundChainId || stateChainID; - const appProvider = getProviderByChainId(chainId!); - if (!appProvider) return; - - const contract = new ethers.Contract(address, RoundABI, appProvider); - const pinataClient = new PinataClient(getConfig()); - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingApplicationsStartTime, + const v2Round = await dataLayer.getRoundByIdAndChainId({ + roundId, + chainId, }); - let applicationsStartTime; - try { - const ast: BigNumber = await contract.applicationsStartTime(); - applicationsStartTime = ast.toNumber(); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error( - `contract: error loading application start time ${contract.address}` - ); - dispatch(loadingError(address, "error loading application start time")); - console.error(e); + if (!v2Round || !v2Round.roundMetadata || !v2Round.applicationMetadata) { + dispatch(loadingError(roundId, "round not found")); return; } - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingApplicationsEndTime, - }); - - let applicationsEndTime; - try { - const aet: BigNumber = await contract.applicationsEndTime(); - // fixes infinite applicationsEndTime representation - applicationsEndTime = isTooBig(aet) - ? Number.MAX_SAFE_INTEGER - : aet.toNumber(); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error( - `contract: error loading application end time ${contract.address}` - ); - dispatch(loadingError(address, "error loading application end time")); - console.error(e); - return; - } - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingRoundStartTime, - }); - - let roundStartTime; - try { - const rst: BigNumber = await contract.roundStartTime(); - roundStartTime = rst.toNumber(); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error( - `contract: error loading round start time ${contract.address}` - ); - dispatch(loadingError(address, "error loading round start time")); - console.error(e); - return; - } - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingRoundEndTime, - }); - - let roundEndTime; - try { - const ret: BigNumber = await contract.roundEndTime(); - // fixes infinite roundEndTime representation - roundEndTime = isTooBig(ret) ? Number.MAX_SAFE_INTEGER : ret.toNumber(); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error( - `contract: error loading round end time ${contract.address}` - ); - dispatch(loadingError(address, "error loading round end time")); - console.error(e); - return; - } - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingToken, - }); - - let token; - try { - token = await contract.token(); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error( - `contract: error loading round token ${contract.address}` - ); - dispatch(loadingError(address, "error loading round token")); - console.error(e); - return; - } + const applicationMetadata = parseRoundApplicationMetadata( + v2Round.applicationMetadata + ); - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingRoundMetaPtr, - }); - - let roundMetaPtr: MetaPtr; - try { - roundMetaPtr = await contract.roundMetaPtr(); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error( - `contract: error loading round metaPtr ${contract.address}` - ); - dispatch(loadingError(address, "error loading round metaPtr")); - console.error(e); - return; - } - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingRoundMetadata, - }); - - let roundMetadata: RoundMetadata; - try { - const resp = await pinataClient.fetchText(roundMetaPtr.pointer); - roundMetadata = JSON.parse(resp); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error( - `contract: error loading round metadata ${contract.address}` - ); - dispatch(loadingError(address, "error loading round metadata")); - console.error(e); - return; - } - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingApplicationMetaPtr, - }); - - let applicationMetaPtr: MetaPtr; - try { - applicationMetaPtr = await contract.applicationMetaPtr(); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error( - `contract: error loading application metaPtr ${contract.address}` - ); - dispatch(loadingError(address, "error loading application metaPtr")); - console.error(e); - return; - } - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingApplicationMetadata, - }); - - let applicationMetadata: RoundApplicationMetadata; - try { - const resp = await pinataClient.fetchText(applicationMetaPtr.pointer); - applicationMetadata = parseRoundApplicationMetadata(JSON.parse(resp)); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error("ipfs: error loading application metadata"); - dispatch(loadingError(address, "error loading application metadata")); - console.error(e); - return; - } - - let programName = ""; - - if (roundMetadata.programContractAddress !== undefined) { - const programContract = new ethers.Contract( - roundMetadata.programContractAddress, - ProgramABI, - appProvider - ); - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingProgramMetaPtr, - }); - - let programMetaPtr: MetaPtr; - try { - programMetaPtr = await programContract.metaPtr(); - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error( - `contract: error loading program metaPtr ${programContract.address}` - ); - dispatch(loadingError(address, "error loading program metaPtr")); - console.error(e); - return; - } - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingProgramMetadata, - }); - - let programMetadata: ProgramMetadata; - try { - const resp = await pinataClient.fetchText(programMetaPtr.pointer); - programMetadata = JSON.parse(resp); - programName = programMetadata.name; - } catch (e) { - datadogRum.addError(e); - datadogLogs.logger.error("ipfs: error loading program metadata"); - dispatch(loadingError(address, "error loading program metadata")); - console.error(e); - return; - } - } - - dispatch({ - type: ROUNDS_LOADING_ROUND, - address, - status: Status.LoadingRoundPayoutStrategy, - }); + const programName = + (await dataLayer.getProgramName({ + projectId: v2Round.roundMetadata.programContractAddress, + })) || ""; + // TODO: FETCH FROM INDEXER let roundPayoutStrategy: PayoutStrategy; try { const resp = await graphqlFetch( @@ -341,7 +109,7 @@ export const loadRound = } `, chainId!, - { roundId: address.toLowerCase() } + { roundId: roundId.toLowerCase() } ); roundPayoutStrategy = resp.data.rounds[0].payoutStrategy ? resp.data.rounds[0].payoutStrategy.strategyName @@ -349,31 +117,31 @@ export const loadRound = } catch (e) { datadogRum.addError(e); datadogLogs.logger.error("sg: error loading round payoutStrategy"); - dispatch(loadingError(address, "error loading round payoutStrategy")); + dispatch(loadingError(roundId, "error loading round payoutStrategy")); console.error(e); return; } const round = { - address, - applicationsStartTime, - applicationsEndTime, - roundStartTime, - roundEndTime, - token, + address: roundId, + applicationsStartTime: Date.parse(v2Round.applicationsStartTime) / 1000, + applicationsEndTime: Date.parse(v2Round.applicationsEndTime) / 1000, + roundStartTime: Date.parse(v2Round.donationsStartTime) / 1000, + roundEndTime: Date.parse(v2Round.donationsEndTime) / 1000, + token: v2Round.matchTokenAddress, roundMetaPtr: { - protocol: BigNumber.from(roundMetaPtr.protocol).toString(), - pointer: roundMetaPtr.pointer, + protocol: "1", + pointer: v2Round.roundMetadataCid, }, - roundMetadata, + roundMetadata: v2Round.roundMetadata, applicationMetaPtr: { - protocol: BigNumber.from(applicationMetaPtr.protocol).toString(), - pointer: applicationMetaPtr.pointer, + protocol: "1", + pointer: v2Round.applicationMetadataCid, }, applicationMetadata, programName, payoutStrategy: roundPayoutStrategy, }; - dispatch(roundLoaded(address, round)); + dispatch(roundLoaded(roundId, round)); }; diff --git a/packages/builder/src/components/application/AboutProject.tsx b/packages/builder/src/components/application/AboutProject.tsx index 9afdb241de..177c59f320 100644 --- a/packages/builder/src/components/application/AboutProject.tsx +++ b/packages/builder/src/components/application/AboutProject.tsx @@ -1,14 +1,17 @@ -import { useEnsName } from "wagmi"; import { GlobeAltIcon } from "@heroicons/react/24/solid"; import { ChainId } from "common"; -import { Metadata, RoundApplicationQuestion } from "../../types"; -import { RoundApplicationAnswers } from "../../types/roundApplication"; +import { + RoundApplicationAnswers, + RoundApplicationQuestion, +} from "data-layer/dist/roundApplication.types"; +import { useEnsName } from "wagmi"; +import { GithubLogo, TwitterLogo } from "../../assets"; import useValidateCredential from "../../hooks/useValidateCredential"; -import { getPayoutIcon } from "../../utils/wallet"; -import Calendar from "../icons/Calendar"; import colors from "../../styles/colors"; -import { GithubLogo, TwitterLogo } from "../../assets"; +import { Metadata } from "../../types"; +import { getPayoutIcon } from "../../utils/wallet"; import GreenVerifiedBadge from "../badges/GreenVerifiedBadge"; +import Calendar from "../icons/Calendar"; import { DetailSummary } from "./DetailSummary"; export function AboutProject(props: { diff --git a/packages/builder/src/components/application/Form.tsx b/packages/builder/src/components/application/Form.tsx index ecb8ed2f7e..3c1e11b16d 100644 --- a/packages/builder/src/components/application/Form.tsx +++ b/packages/builder/src/components/application/Form.tsx @@ -5,6 +5,10 @@ import { ExclamationTriangleIcon, InformationCircleIcon, } from "@heroicons/react/24/solid"; +import { + RoundApplicationAnswers, + RoundApplicationMetadata, +} from "data-layer/dist/roundApplication.types"; import { Fragment, useEffect, useState } from "react"; import { shallowEqual, useDispatch, useSelector } from "react-redux"; import { Link } from "react-router-dom"; @@ -22,10 +26,6 @@ import { ProjectOption, Round, } from "../../types"; -import { - RoundApplicationAnswers, - RoundApplicationMetadata, -} from "../../types/roundApplication"; import { ROUND_PAYOUT_DIRECT, getProjectURIComponents, @@ -359,7 +359,7 @@ export default function Form({ }`} >
e.preventDefault()}> - {schema.questions.map((input) => { + {schema.questions.map((input: any) => { if ( needsProject && input.type !== "project" && @@ -619,7 +619,7 @@ export default function Form({ } name={`${input.id}`} value={answers[input.id] as string} - options={input.options.map((o) => ({ + options={input.options.map((o: any) => ({ id: o, title: o, }))} diff --git a/packages/builder/src/components/application/FullPreview.tsx b/packages/builder/src/components/application/FullPreview.tsx index 5ab2a6b904..b2329d1e15 100644 --- a/packages/builder/src/components/application/FullPreview.tsx +++ b/packages/builder/src/components/application/FullPreview.tsx @@ -1,9 +1,12 @@ -import { useEffect } from "react"; import { EyeIcon } from "@heroicons/react/24/solid"; import { ChainId, renderToHTML } from "common"; -import { Metadata, RoundApplicationQuestion } from "../../types"; -import { RoundApplicationAnswers } from "../../types/roundApplication"; +import { + RoundApplicationAnswers, + RoundApplicationQuestion, +} from "data-layer/dist/roundApplication.types"; +import { useEffect } from "react"; import { DefaultProjectBanner, DefaultProjectLogo } from "../../assets"; +import { Metadata } from "../../types"; import Button, { ButtonVariants } from "../base/Button"; import { AboutProject } from "./AboutProject"; import { ProjectTitle } from "./ProjectTitle"; diff --git a/packages/builder/src/components/base/formValidation.ts b/packages/builder/src/components/base/formValidation.ts index c9cf3b464d..95c62291fb 100644 --- a/packages/builder/src/components/base/formValidation.ts +++ b/packages/builder/src/components/base/formValidation.ts @@ -1,9 +1,9 @@ -import { array, object, string, number } from "yup"; -import { FormInputs } from "../../types"; import { RoundApplicationAnswers, RoundApplicationQuestion, -} from "../../types/roundApplication"; +} from "data-layer/dist/roundApplication.types"; +import { array, number, object, string } from "yup"; +import { FormInputs } from "../../types"; const urlRegex = /^(?:https?:\/\/)?(?:www\.)?[A-Za-z0-9]+\.[A-Za-z]{2,}(?:\/.*)?$/; diff --git a/packages/builder/src/components/grants/About.tsx b/packages/builder/src/components/grants/About.tsx index 0558399e88..fddc7dd71a 100644 --- a/packages/builder/src/components/grants/About.tsx +++ b/packages/builder/src/components/grants/About.tsx @@ -1,10 +1,8 @@ import { Box } from "@chakra-ui/react"; import { renderToHTML } from "common"; -import { useSelector } from "react-redux"; -import { useParams } from "react-router-dom"; +import { ProjectApplication } from "data-layer"; import { GithubLogo, TwitterLogo } from "../../assets"; import useValidateCredential from "../../hooks/useValidateCredential"; -import { RootState } from "../../reducers"; import colors from "../../styles/colors"; import { ApplicationCardType, @@ -13,37 +11,25 @@ import { Project, } from "../../types"; import { formatDateFromMs } from "../../utils/components"; +import GreenVerifiedBadge from "../badges/GreenVerifiedBadge"; import Calendar from "../icons/Calendar"; import LinkIcon from "../icons/LinkIcon"; import ApplicationCard from "./ApplicationCard"; -import GreenVerifiedBadge from "../badges/GreenVerifiedBadge"; export default function About({ project, + applications, showApplications, createdAt, updatedAt, }: { project?: Metadata | FormInputs | Project; + applications: ProjectApplication[]; showApplications: boolean; createdAt: number; updatedAt: number; }) { - const params = useParams(); - const props = useSelector((state: RootState) => { - const { chainId } = params; - - const applications = state.projects.applications[params.id!] || []; - - return { - chainId, - projectID: params.id!, - applications, - }; - }); - - const canShowApplications = - props.applications.length !== 0 && showApplications; + const canShowApplications = applications.length !== 0 && showApplications; const { isValid: validTwitterCredential } = useValidateCredential( project?.credentials?.twitter, @@ -61,8 +47,8 @@ export default function About({ My Applications - {props.applications.map((application, index) => { - const roundID = application?.roundID; + {applications.map((application, index) => { + const roundID = application?.roundId; const cardData: ApplicationCardType = { application, roundID, diff --git a/packages/builder/src/components/grants/ApplicationCard.tsx b/packages/builder/src/components/grants/ApplicationCard.tsx index dbf2ab5a92..d313187f9d 100644 --- a/packages/builder/src/components/grants/ApplicationCard.tsx +++ b/packages/builder/src/components/grants/ApplicationCard.tsx @@ -1,29 +1,34 @@ import { Badge, Box, Button, Image, Spinner } from "@chakra-ui/react"; -import { useEffect, useState } from "react"; +import { ApplicationStatus, useDataLayer } from "data-layer"; +import { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { Link } from "react-router-dom"; import { loadRound } from "../../actions/rounds"; import { RootState } from "../../reducers"; -import { AppStatus } from "../../reducers/projects"; +import { PayoutStrategy } from "../../reducers/rounds"; import { roundApplicationViewPath } from "../../routes"; -import { Round, RoundSupport, ApplicationCardType } from "../../types"; +import { ApplicationCardType, RoundSupport } from "../../types"; import { formatDateFromSecs, isInfinite } from "../../utils/components"; -import { getNetworkIcon, networkPrettyName } from "../../utils/wallet"; -import { PayoutStrategy } from "../../reducers/rounds"; import { ROUND_PAYOUT_DIRECT } from "../../utils/utils"; +import { getNetworkIcon, networkPrettyName } from "../../utils/wallet"; export default function ApplicationCard({ applicationData, }: { applicationData: ApplicationCardType; }) { - const [roundData, setRoundData] = useState(); + // const [roundData, setRoundData] = useState(); + const dataLayer = useDataLayer(); const dispatch = useDispatch(); + const props = useSelector((state: RootState) => { const roundState = state.rounds[applicationData.roundID]; const round = roundState ? roundState.round : undefined; + const support: RoundSupport | undefined = round?.roundMetadata?.support; + const payoutStrategy = round?.payoutStrategy; + const applicationChainName = networkPrettyName( Number(applicationData.chainId) ); @@ -31,38 +36,35 @@ export default function ApplicationCard({ Number(applicationData.chainId) ); - const isDirectRound = round && round.payoutStrategy === ROUND_PAYOUT_DIRECT; + const isDirectRound = payoutStrategy === ROUND_PAYOUT_DIRECT; return { round, isDirectRound, support, + payoutStrategy, applicationChainName, applicationChainIconUri, }; }); - const renderApplicationDate = () => - roundData && ( - <> - {formatDateFromSecs(roundData.applicationsStartTime)} -{" "} - {!isInfinite(roundData.applicationsEndTime) - ? formatDateFromSecs(roundData.applicationsEndTime) - : "No End Date"} - - ); - useEffect(() => { if (applicationData.roundID !== undefined) { - dispatch(loadRound(applicationData.roundID, applicationData.chainId)); + dispatch( + loadRound(applicationData.roundID, dataLayer, applicationData.chainId) + ); } }, [dispatch, applicationData.roundID]); - useEffect(() => { - if (props.round) { - setRoundData(props.round); - } - }, [props.round]); + const renderApplicationDate = () => + props.round && ( + <> + {formatDateFromSecs(props.round?.applicationsStartTime!)} -{" "} + {!isInfinite(Number(props.round?.applicationsEndTime!)) + ? formatDateFromSecs(props.round?.applicationsEndTime!) + : "No End Date"} + + ); const renderRoundBadge = () => { let colorScheme: @@ -72,7 +74,7 @@ export default function ApplicationCard({ } | undefined; - switch (roundData?.payoutStrategy as PayoutStrategy) { + switch (props.payoutStrategy as PayoutStrategy) { case "MERKLE": colorScheme = { bg: "#E6FFF9", @@ -90,7 +92,7 @@ export default function ApplicationCard({ break; } - const roundPayoutStrategy = roundData?.payoutStrategy; + const roundPayoutStrategy = props.payoutStrategy; return ( @@ -123,7 +125,7 @@ export default function ApplicationCard({ text: string; } | undefined; - switch (applicationData.application.status as AppStatus) { + switch (applicationData.application.status as ApplicationStatus) { case "APPROVED": colorScheme = { bg: "#E6FFF9", @@ -154,7 +156,6 @@ export default function ApplicationCard({ } const applicationStatus = applicationData.application.status; - const isDirectRound = props.round?.payoutStrategy === ROUND_PAYOUT_DIRECT; const applicationInReview = applicationData.application.inReview; return ( @@ -166,12 +167,12 @@ export default function ApplicationCard({ textTransform="inherit" > {applicationStatus === "PENDING" && - isDirectRound && + props.isDirectRound && !applicationInReview ? ( Received ) : null} - {(applicationStatus === "PENDING" && !isDirectRound) || - (isDirectRound && applicationInReview) ? ( + {(applicationStatus === "PENDING" && !props.isDirectRound) || + (props.isDirectRound && applicationInReview) ? ( In Review ) : null} {applicationStatus === "REJECTED" ? ( @@ -197,7 +198,7 @@ export default function ApplicationCard({ > - {props.round?.programName} + {props.round?.roundMetadata.name}
@@ -211,7 +212,7 @@ export default function ApplicationCard({
{props.round?.roundMetadata.name}
- {roundData ? {renderApplicationDate()} : } + {props.round ? {renderApplicationDate()} : }
{renderRoundBadge()} {renderApplicationBadge()} @@ -229,7 +230,7 @@ export default function ApplicationCard({ }`} rel="noreferrer" > - Contact the {props.round?.programName} support team. + Contact the {props.round?.roundMetadata.name} support team.

)} @@ -237,7 +238,7 @@ export default function ApplicationCard({ to={roundApplicationViewPath( applicationData.chainId.toString(), applicationData.roundID, - applicationData.application.metaPtr?.pointer || "" + applicationData.application.metadataCid || "" )} >