From fee3a52e97c2191c0e425d97039e5d71498712fb Mon Sep 17 00:00:00 2001 From: Johnny D Date: Thu, 13 Jun 2024 10:55:24 +1000 Subject: [PATCH] DB refactor [4/n]: switch DB queries to subgraph (#4366) Co-authored-by: aeolian <94939382+aeolianeth@users.noreply.github.com> --- .../AccountDashboard/AccountDashboard.tsx | 39 ++++++++++++------- .../hooks/useProjectUnwatchCellData.ts | 19 ++++++--- .../CaseStudies/ReadMoreCaseStudies.tsx | 15 +++++-- src/components/Home/HomepageProjectCard.tsx | 12 ++---- .../JuicyPicksSection/JuicyPicksSection.tsx | 11 +++++- .../SpotlightProjectCard.tsx | 4 +- .../JuicyPicksSection/hooks/useJuicyPicks.ts | 33 ++++++---------- .../SuccessStoriesCard.tsx | 4 +- .../SuccessStoriesSection.tsx | 15 +++++-- src/components/Home/TopSection/TopSection.tsx | 14 +++++-- src/components/ProjectCard.tsx | 7 ++-- src/contexts/v1/Project/useV1ProjectState.ts | 21 +++++----- .../v2v3/Project/useV2V3ProjectState.ts | 22 ++++++----- src/graphql/projects/projects.graphql | 17 +++++++- src/models/subgraphProjects.ts | 3 ++ 15 files changed, 147 insertions(+), 89 deletions(-) create mode 100644 src/models/subgraphProjects.ts diff --git a/src/components/AccountDashboard/AccountDashboard.tsx b/src/components/AccountDashboard/AccountDashboard.tsx index b3a334c1ac..3b1b8c01fe 100644 --- a/src/components/AccountDashboard/AccountDashboard.tsx +++ b/src/components/AccountDashboard/AccountDashboard.tsx @@ -15,10 +15,11 @@ import WalletContributionCard from 'components/WalletContributionCard' import { OrderDirection, Participant_OrderBy, + Project_OrderBy, + useProjectsQuery, useWalletContributionsQuery, } from 'generated/graphql' import useMobile from 'hooks/useMobile' -import { useDBProjectsQuery } from 'hooks/useProjects' import { useWalletBookmarkedIds, useWalletBookmarkedProjects, @@ -27,7 +28,7 @@ import { useWalletSignIn } from 'hooks/useWalletSignIn' import { useWallet } from 'hooks/Wallet' import { client } from 'lib/apollo/client' import { Profile } from 'models/database' -import { DBProject } from 'models/dbProject' +import { SubgraphQueryProject } from 'models/subgraphProjects' import Link from 'next/link' import { useRouter } from 'next/router' import { useCallback, useState } from 'react' @@ -35,7 +36,7 @@ import { isEqualAddress } from 'utils/address' import { ensAvatarUrlForAddress } from 'utils/ens' import { etherscanLink } from 'utils/etherscan' -function ProjectsList({ projects }: { projects: DBProject[] }) { +function ProjectsList({ projects }: { projects: SubgraphQueryProject[] }) { const { userAddress } = useWallet() const { ids: bookmarkedProjectIds } = useWalletBookmarkedIds({ @@ -127,15 +128,22 @@ function ContributedList({ address }: { address: string }) { } function OwnedProjectsList({ address }: { address: string }) { - const { data: projects, isLoading } = useDBProjectsQuery({ - owner: address, - orderBy: 'created_at', - orderDirection: 'desc', + const { data, loading } = useProjectsQuery({ + client, + variables: { + where: { + owner: address, + }, + orderBy: Project_OrderBy.createdAt, + orderDirection: OrderDirection.desc, + }, }) + const projects = data?.projects + const { userAddress } = useWallet() - if (isLoading) return + if (loading) return if (!projects || projects.length === 0) return ( @@ -191,15 +199,20 @@ function SavedProjectsList({ address }: { address: string }) { } function CreatedProjectsList({ address }: { address: string }) { - const { data: projects, isLoading } = useDBProjectsQuery({ - creator: address, - orderBy: 'created_at', - orderDirection: 'desc', + const { data, loading } = useProjectsQuery({ + client, + variables: { + where: { + owner: address, + }, + }, }) + const projects = data?.projects + const { userAddress } = useWallet() - if (isLoading) return + if (loading) return if (!projects || projects.length === 0) return ( diff --git a/src/components/AccountSettingsDashboard/hooks/useProjectUnwatchCellData.ts b/src/components/AccountSettingsDashboard/hooks/useProjectUnwatchCellData.ts index 31da45f01f..d9f123080d 100644 --- a/src/components/AccountSettingsDashboard/hooks/useProjectUnwatchCellData.ts +++ b/src/components/AccountSettingsDashboard/hooks/useProjectUnwatchCellData.ts @@ -1,5 +1,7 @@ import { PV_V2 } from 'constants/pv' -import { useDBProjectsQuery } from 'hooks/useProjects' +import { useProjectsQuery } from 'generated/graphql' +import { client } from 'lib/apollo/client' +import { SubgraphQueryProject } from 'models/subgraphProjects' /** * Fetches project data from the subgraph, using the project id as a key. @@ -10,11 +12,16 @@ export const useProjectUnwatchCellData = ({ projectId, }: { projectId: number -}) => { - const { data } = useDBProjectsQuery({ - projectId, - pv: [PV_V2], +}): SubgraphQueryProject | undefined => { + const { data } = useProjectsQuery({ + client, + variables: { + where: { + projectId, + pv: PV_V2, + }, + }, }) - return data?.[0] + return data?.projects[0] } diff --git a/src/components/CaseStudies/ReadMoreCaseStudies.tsx b/src/components/CaseStudies/ReadMoreCaseStudies.tsx index a9747e5a4f..21a1523ec2 100644 --- a/src/components/CaseStudies/ReadMoreCaseStudies.tsx +++ b/src/components/CaseStudies/ReadMoreCaseStudies.tsx @@ -2,7 +2,8 @@ import { Trans } from '@lingui/macro' import { ProjectCarousel } from 'components/Home/ProjectCarousel' import { SuccessStoriesCard } from 'components/Home/SuccessStoriesSection/SuccessStoriesCard' import { CASE_STUDY_PROJECTS } from 'constants/successStoryProjects' -import { useDBProjectsQuery } from 'hooks/useProjects' +import { useProjectsQuery } from 'generated/graphql' +import { client } from 'lib/apollo/client' export function ReadMoreCaseStudies({ currentProject, @@ -13,14 +14,20 @@ export function ReadMoreCaseStudies({ p => p.id !== currentProject, ) - const { data } = useDBProjectsQuery({ - ids: otherCaseStudies.map(p => p.id), + const { data } = useProjectsQuery({ + client, + variables: { + where: { + id_in: otherCaseStudies.map(p => p.id), + }, + }, }) + const projects = data?.projects if (!data) return null const readMoreProjects = CASE_STUDY_PROJECTS.map(p => { - const project = data.find(proj => proj.id === p.id) + const project = projects?.find(proj => proj.id === p.id) if (!project) return return { diff --git a/src/components/Home/HomepageProjectCard.tsx b/src/components/Home/HomepageProjectCard.tsx index 7b95b828ca..75d7e9ec23 100644 --- a/src/components/Home/HomepageProjectCard.tsx +++ b/src/components/Home/HomepageProjectCard.tsx @@ -5,7 +5,7 @@ import ProjectLogo from 'components/ProjectLogo' import ETHAmount from 'components/currency/ETHAmount' import { PV_V2 } from 'constants/pv' import { useProjectMetadata } from 'hooks/useProjectMetadata' -import { DBProject } from 'models/dbProject' +import { SubgraphQueryProject } from 'models/subgraphProjects' import { v2v3ProjectRoute } from 'utils/routes' function Statistic({ @@ -42,14 +42,8 @@ export function HomepageProjectCard({ lazyLoad, }: { project: Pick< - DBProject, - | 'terminal' - | 'metadataUri' - | 'volume' - | 'paymentsCount' - | 'handle' - | 'pv' - | 'projectId' + SubgraphQueryProject, + 'metadataUri' | 'volume' | 'paymentsCount' | 'handle' | 'pv' | 'projectId' > lazyLoad?: boolean }) { diff --git a/src/components/Home/JuicyPicksSection/JuicyPicksSection.tsx b/src/components/Home/JuicyPicksSection/JuicyPicksSection.tsx index 3f2c95d3d5..3ccbdc67fc 100644 --- a/src/components/Home/JuicyPicksSection/JuicyPicksSection.tsx +++ b/src/components/Home/JuicyPicksSection/JuicyPicksSection.tsx @@ -9,13 +9,22 @@ import { SectionContainer } from 'components/Home/SectionContainer' import { SectionHeading } from 'components/Home/SectionHeading' import { XLButton } from 'components/buttons/XLButton' import { useMedia } from 'contexts/Theme/useMedia' +import { Project } from 'generated/graphql' import Link from 'next/link' +import { JUICY_PICKS_PROJECT_IDS } from './constants' export function JuicyPicksSection() { - const { data: projects } = useFetchJuicyPicks() + const juicyPicksQuery = useFetchJuicyPicks() const isCarouselBreakpoint = useMedia('(max-width: 1079px)') + // ensure list sorted by JUICY_PICKS_PROJECT_IDS array order + const projects = JUICY_PICKS_PROJECT_IDS.map(projectId => { + return juicyPicksQuery.data?.projects.find( + project => project.projectId === projectId, + ) as Project | undefined + }).filter((p): p is Project => !!p) + if (!projects) { return null } diff --git a/src/components/Home/JuicyPicksSection/SpotlightProjectCard.tsx b/src/components/Home/JuicyPicksSection/SpotlightProjectCard.tsx index 8052be5c1c..c9f65e0a1d 100644 --- a/src/components/Home/JuicyPicksSection/SpotlightProjectCard.tsx +++ b/src/components/Home/JuicyPicksSection/SpotlightProjectCard.tsx @@ -9,9 +9,9 @@ import Paragraph from 'components/Paragraph' import ProjectLogo from 'components/ProjectLogo' import { TRENDING_WINDOW_DAYS } from 'components/Projects/RankingExplanation' import ETHAmount from 'components/currency/ETHAmount' +import { Project } from 'generated/graphql' import { useProjectMetadata } from 'hooks/useProjectMetadata' import { useProjectTrendingPercentageIncrease } from 'hooks/useProjects' -import { DBProject } from 'models/dbProject' import Link from 'next/link' import { twJoin } from 'tailwind-merge' import { ipfsUriToGatewayUrl } from 'utils/ipfs' @@ -36,7 +36,7 @@ function Statistic({ ) } -export function SpotlightProjectCard({ project }: { project: DBProject }) { +export function SpotlightProjectCard({ project }: { project: Project }) { const { data: metadata } = useProjectMetadata(project.metadataUri) const percentageGain = useProjectTrendingPercentageIncrease({ diff --git a/src/components/Home/JuicyPicksSection/hooks/useJuicyPicks.ts b/src/components/Home/JuicyPicksSection/hooks/useJuicyPicks.ts index 6b7039a4d1..34ccea3352 100644 --- a/src/components/Home/JuicyPicksSection/hooks/useJuicyPicks.ts +++ b/src/components/Home/JuicyPicksSection/hooks/useJuicyPicks.ts @@ -1,29 +1,18 @@ import { JUICY_PICKS_PROJECT_IDS } from 'components/Home/JuicyPicksSection/constants' import { PV_V2 } from 'constants/pv' -import { useDBProjectsQuery } from 'hooks/useProjects' -import { DBProject } from 'models/dbProject' +import { useProjectsQuery } from 'generated/graphql' +import { client } from 'lib/apollo/client' import { getSubgraphIdForProject } from 'utils/graph' export function useFetchJuicyPicks() { - const res = useDBProjectsQuery({ - ids: JUICY_PICKS_PROJECT_IDS.map(projectId => - getSubgraphIdForProject(PV_V2, projectId), - ), + return useProjectsQuery({ + client, + variables: { + where: { + id_in: JUICY_PICKS_PROJECT_IDS.map(projectId => + getSubgraphIdForProject(PV_V2, projectId), + ), + }, + }, }) - - if (!res.data) { - return res - } - - // ensure list sorted by JUICY_PICKS_PROJECT_IDS array order - const sortedPicks = JUICY_PICKS_PROJECT_IDS.map(projectId => { - return res.data?.find(project => project.projectId === projectId) as - | DBProject - | undefined - }).filter((p): p is DBProject => !!p) - - return { - ...res, - data: sortedPicks, - } } diff --git a/src/components/Home/SuccessStoriesSection/SuccessStoriesCard.tsx b/src/components/Home/SuccessStoriesSection/SuccessStoriesCard.tsx index 8ed2655adf..62b9f0487b 100644 --- a/src/components/Home/SuccessStoriesSection/SuccessStoriesCard.tsx +++ b/src/components/Home/SuccessStoriesSection/SuccessStoriesCard.tsx @@ -4,7 +4,6 @@ import { Badge } from 'components/Badge' import ETHAmount from 'components/currency/ETHAmount' import ProjectLogo from 'components/ProjectLogo' import { useProjectMetadata } from 'hooks/useProjectMetadata' -import { DBProject } from 'models/dbProject' import { ProjectTagName, projectTagText } from 'models/project-tags' import Image from 'next/image' import Link from 'next/link' @@ -14,6 +13,7 @@ import { HOMEPAGE_CARD_BORDER, HOMEPAGE_CARD_BORDER_HOVER, } from 'components/Home/HomepageCard' +import { SubgraphQueryProject } from 'models/subgraphProjects' function SuccessStoriesCardTag({ tag }: { tag: ProjectTagName }) { const text = projectTagText[tag]() @@ -33,7 +33,7 @@ export function SuccessStoriesCard({ nameOverride, imageOverride, }: { - project: DBProject + project: SubgraphQueryProject tags: ProjectTagName[] nameOverride?: string imageOverride?: string diff --git a/src/components/Home/SuccessStoriesSection/SuccessStoriesSection.tsx b/src/components/Home/SuccessStoriesSection/SuccessStoriesSection.tsx index 5dd8dd8c4e..73b18a97be 100644 --- a/src/components/Home/SuccessStoriesSection/SuccessStoriesSection.tsx +++ b/src/components/Home/SuccessStoriesSection/SuccessStoriesSection.tsx @@ -6,20 +6,27 @@ import { SuccessStoriesCard } from 'components/Home/SuccessStoriesSection/Succes import { XLButton } from 'components/buttons/XLButton' import { CASE_STUDY_PROJECTS } from 'constants/successStoryProjects' import { useMedia } from 'contexts/Theme/useMedia' -import { useDBProjectsQuery } from 'hooks/useProjects' +import { useProjectsQuery } from 'generated/graphql' +import { client } from 'lib/apollo/client' import Link from 'next/link' export function SuccessStoriesSection() { - const { data } = useDBProjectsQuery({ - ids: CASE_STUDY_PROJECTS.map(p => p.id), + const { data } = useProjectsQuery({ + client, + variables: { + where: { + id_in: CASE_STUDY_PROJECTS.map(p => p.id), + }, + }, }) + const projects = data?.projects const isXl = useMedia('(min-width: 1280px)') if (!data) return null const topProjects = CASE_STUDY_PROJECTS.map(p => { - const project = data.find(proj => proj.id === p.id) + const project = projects?.find(proj => proj.id === p.id) if (!project) return return { diff --git a/src/components/Home/TopSection/TopSection.tsx b/src/components/Home/TopSection/TopSection.tsx index 8e721dc293..af771501d5 100644 --- a/src/components/Home/TopSection/TopSection.tsx +++ b/src/components/Home/TopSection/TopSection.tsx @@ -12,11 +12,12 @@ import { ProjectTag } from 'components/ProjectTags/ProjectTag' import { XLButton } from 'components/buttons/XLButton' import { HOMEPAGE } from 'constants/fathomEvents' import { PV_V1 } from 'constants/pv' +import { useProjectsQuery } from 'generated/graphql' import { DEFAULT_TRENDING_PROJECTS_LIMIT, - useDBProjectsQuery, useTrendingProjects, } from 'hooks/useProjects' +import { client } from 'lib/apollo/client' import { trackFathomGoal } from 'lib/fathom' import { ProjectTagName } from 'models/project-tags' import Link from 'next/link' @@ -42,9 +43,16 @@ export function TopSection() { const { data: trendingProjects, isLoading } = useTrendingProjects( DEFAULT_TRENDING_PROJECTS_LIMIT, ) - const { data: backupProjects } = useDBProjectsQuery({ - ids: BACKUP_PROJECTS, + + const { data } = useProjectsQuery({ + client, + variables: { + where: { + id_in: BACKUP_PROJECTS, + }, + }, }) + const backupProjects = data?.projects const remainderProjectCount = DEFAULT_TRENDING_PROJECTS_LIMIT - (trendingProjects?.length ?? 0) diff --git a/src/components/ProjectCard.tsx b/src/components/ProjectCard.tsx index ef56a33d26..ba76b1d585 100644 --- a/src/components/ProjectCard.tsx +++ b/src/components/ProjectCard.tsx @@ -10,7 +10,7 @@ import { v2v3ProjectRoute } from 'utils/routes' import { useProjectMetadata } from 'hooks/useProjectMetadata' import { useSubtitle } from 'hooks/useSubtitle' -import { DBProject } from 'models/dbProject' +import { SubgraphQueryProject } from 'models/subgraphProjects' import { ArchivedBadge } from './ArchivedBadge' import Loading from './Loading' import ProjectLogo from './ProjectLogo' @@ -21,7 +21,7 @@ export default function ProjectCard({ project, bookmarked, }: { - project?: DBProject + project?: SubgraphQueryProject bookmarked?: boolean }) { const { data: metadata } = useProjectMetadata(project?.metadataUri) @@ -34,7 +34,8 @@ export default function ProjectCard({ if (!project) return null - const { volume, pv, handle, projectId, tags, createdAt } = project + const { volume, pv, handle, projectId, createdAt } = project + const tags = metadata?.tags // If the total paid is greater than 0, but less than 10 ETH, show two decimal places. const precision = volume?.gt(0) && volume.lt(constants.WeiPerEther) ? 2 : 0 diff --git a/src/contexts/v1/Project/useV1ProjectState.ts b/src/contexts/v1/Project/useV1ProjectState.ts index 41e9ce3bde..25bf0a8cc6 100644 --- a/src/contexts/v1/Project/useV1ProjectState.ts +++ b/src/contexts/v1/Project/useV1ProjectState.ts @@ -1,9 +1,9 @@ import { PV_V1 } from 'constants/pv' import { ProjectMetadataContext } from 'contexts/shared/ProjectMetadataContext' import { V1ProjectContextType } from 'contexts/v1/Project/V1ProjectContext' +import { useProjectsQuery } from 'generated/graphql' import useSymbolOfERC20 from 'hooks/ERC20/useSymbolOfERC20' import { useCurrencyConverter } from 'hooks/useCurrencyConverter' -import { useDBProjectsQuery } from 'hooks/useProjects' import useBalanceOfProject from 'hooks/v1/contractReader/useBalanceOfProject' import useCurrentFundingCycleOfProject from 'hooks/v1/contractReader/useCurrentFundingCycleOfProject' import useCurrentPayoutModsOfProject from 'hooks/v1/contractReader/useCurrentPayoutModsOfProject' @@ -16,6 +16,7 @@ import useQueuedTicketModsOfProject from 'hooks/v1/contractReader/useQueuedTicke import useTerminalOfProject from 'hooks/v1/contractReader/useTerminalOfProject' import useTokenAddressOfProject from 'hooks/v1/contractReader/useTokenAddressOfProject' import { useV1TerminalVersion } from 'hooks/v1/contractReader/useV1TerminalVersion' +import { client } from 'lib/apollo/client' import { V1CurrencyOption } from 'models/v1/currencyOption' import { useContext, useMemo } from 'react' import { V1CurrencyName } from 'utils/v1/currency' @@ -66,15 +67,17 @@ export function useV1ProjectState({ ) const overflow = useOverflowOfProject(projectId, terminalName) - const { data: projects } = useDBProjectsQuery( - projectId - ? { - projectId, - pv: [PV_V1], - } - : null, - ) + const { data } = useProjectsQuery({ + client, + variables: { + where: { + projectId, + pv: PV_V1, + }, + }, + }) + const projects = data?.projects const createdAt = projects?.[0]?.createdAt const earned = projects?.[0]?.volume diff --git a/src/contexts/v2v3/Project/useV2V3ProjectState.ts b/src/contexts/v2v3/Project/useV2V3ProjectState.ts index 80aa4119fe..23748b41ae 100644 --- a/src/contexts/v2v3/Project/useV2V3ProjectState.ts +++ b/src/contexts/v2v3/Project/useV2V3ProjectState.ts @@ -4,10 +4,10 @@ import { RESERVED_TOKEN_SPLIT_GROUP, } from 'constants/splits' import { BigNumber } from 'ethers' +import { useProjectsQuery } from 'generated/graphql' import useNameOfERC20 from 'hooks/ERC20/useNameOfERC20' import useSymbolOfERC20 from 'hooks/ERC20/useSymbolOfERC20' import { useCurrencyConverter } from 'hooks/useCurrencyConverter' -import { useDBProjectsQuery } from 'hooks/useProjects' import { useBallotState } from 'hooks/v2v3/contractReader/useBallotState' import { useETHPaymentTerminalFee } from 'hooks/v2v3/contractReader/useETHPaymentTerminalFee' import { usePaymentTerminalBalance } from 'hooks/v2v3/contractReader/usePaymentTerminalBalance' @@ -21,6 +21,7 @@ import useProjectToken from 'hooks/v2v3/contractReader/useProjectToken' import useProjectTokenTotalSupply from 'hooks/v2v3/contractReader/useProjectTokenTotalSupply' import useTerminalCurrentOverflow from 'hooks/v2v3/contractReader/useTerminalCurrentOverflow' import useUsedDistributionLimit from 'hooks/v2v3/contractReader/useUsedDistributionLimit' +import { client } from 'lib/apollo/client' import first from 'lodash/first' import { V2V3CurrencyOption } from 'models/v2v3/currencyOption' import { useContext, useMemo } from 'react' @@ -84,14 +85,17 @@ export function useV2V3ProjectState({ projectId }: { projectId: number }) { /** * Load project stats */ - const { data: projects } = useDBProjectsQuery( - projectId - ? { - projectId, - pv: [PV_V2], - } - : null, - ) + const { data } = useProjectsQuery({ + client, + variables: { + where: { + projectId, + pv: PV_V2, + }, + }, + }) + + const projects = data?.projects const projectStatsData = first(projects) const { createdAt, diff --git a/src/graphql/projects/projects.graphql b/src/graphql/projects/projects.graphql index 9532a3ef3c..6b00dd7e74 100644 --- a/src/graphql/projects/projects.graphql +++ b/src/graphql/projects/projects.graphql @@ -1,7 +1,20 @@ -query Projects($where: Project_filter, $first: Int, $skip: Int) { +query Projects( + $where: Project_filter, + $first: Int, + $skip: Int, + $orderBy: Project_orderBy + $orderDirection: OrderDirection +) { projects(where: $where, first: $first, skip: $skip) { + id projectId metadataUri handle + createdAt + pv + volume + owner + trendingVolume + paymentsCount } -} \ No newline at end of file +} diff --git a/src/models/subgraphProjects.ts b/src/models/subgraphProjects.ts new file mode 100644 index 0000000000..502585fb9e --- /dev/null +++ b/src/models/subgraphProjects.ts @@ -0,0 +1,3 @@ +import { ProjectsQuery } from 'generated/graphql' + +export type SubgraphQueryProject = ProjectsQuery['projects'][number]