From 082e8aac781a4bfac40f0a7e356a20ffbffaeb2f Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Tue, 22 Oct 2024 12:24:54 +0200 Subject: [PATCH] feat: APP-365 use new buy credits flow on Project cards (#2503) --- .../CreditClassGridCard.tsx | 24 +- .../ProjectCardsSection.tsx | 4 +- .../ProjectCardsSection.types.ts | 4 +- .../SellOrdersActionsBar.tsx | 6 +- .../ProjectDetails.MoreProjects.tsx | 21 +- .../ProjectDetails/ProjectDetails.loader.ts | 9 - .../ProjectDetails/ProjectDetails.tsx | 61 +--- .../ProjectDetails/ProjectDetails.utils.tsx | 30 +- .../ProjectDetails/hooks/useGetProject.ts | 25 +- .../BuySellOrderFlow.constants.ts | 3 - .../BuySellOrderFlow/BuySellOrderFlow.tsx | 328 ------------------ .../hooks/useSelectedProject.tsx | 36 -- .../hooks/useCreateSellOrderData.tsx | 4 +- .../hooks/projects/useProjectsWithOrders.ts | 27 +- .../hooks/useBuySellOrderData.tsx | 18 +- .../src/hooks/useOnBuyButtonClick.ts | 76 ++++ .../projects/normalizeProjectsWithMetadata.ts | 78 ++++- .../src/pages/BuyCredits/BuyCredits.atoms.ts | 1 + .../src/pages/BuyCredits/BuyCredits.tsx | 2 +- .../CreditClassDetails.Projects.tsx | 21 +- .../CreditClassDetails/CreditClassDetails.tsx | 49 +-- .../hooks/useFetchProjectsByAdmin.tsx | 45 +-- .../hooks/useFetchProjectsWithOrders.tsx | 21 +- .../CreditClassTab/CreditClassTab.tsx | 27 +- .../ProjectsTab/ProjectsTab.tsx | 39 ++- .../src/pages/Home/Home.FeaturedProjects.tsx | 21 +- .../pages/Home/hooks/useFeaturedProjects.ts | 5 +- .../Storefront}/hooks/useFetchSellOrders.ts | 0 .../hooks/useNormalizedSellOrders.tsx | 2 +- .../Projects/AllProjects/AllProjects.tsx | 29 +- .../src/pages/Projects/Projects.context.tsx | 5 +- .../hooks/useProjectsSellOrders.types.ts | 6 +- 32 files changed, 326 insertions(+), 701 deletions(-) delete mode 100644 web-marketplace/src/features/marketplace/BuySellOrderFlow/BuySellOrderFlow.constants.ts delete mode 100644 web-marketplace/src/features/marketplace/BuySellOrderFlow/BuySellOrderFlow.tsx delete mode 100644 web-marketplace/src/features/marketplace/BuySellOrderFlow/hooks/useSelectedProject.tsx rename web-marketplace/src/{features/marketplace/BuySellOrderFlow => }/hooks/useBuySellOrderData.tsx (59%) create mode 100644 web-marketplace/src/hooks/useOnBuyButtonClick.ts rename web-marketplace/src/{features/marketplace/BuySellOrderFlow => pages/Marketplace/Storefront}/hooks/useFetchSellOrders.ts (100%) diff --git a/web-components/src/components/molecules/CreditClassGridCard/CreditClassGridCard.tsx b/web-components/src/components/molecules/CreditClassGridCard/CreditClassGridCard.tsx index 723d350f30..d0d27b31ec 100644 --- a/web-components/src/components/molecules/CreditClassGridCard/CreditClassGridCard.tsx +++ b/web-components/src/components/molecules/CreditClassGridCard/CreditClassGridCard.tsx @@ -17,7 +17,7 @@ export interface Props { name: string; imgSrc: string; purchaseInfo?: PurchaseInfo; - button: ButtonType; + button?: ButtonType; href?: string; className?: string; LinkComponent?: LinkComponentType; @@ -36,8 +36,6 @@ export const CreditClassGridCard = ({ LinkComponent = ({ children }) => <>{children}, sx = [], }: Props): JSX.Element => { - const { text, disabled, startIcon, onClick } = button; - return ( - - {text} - + {button && ( + + {button.text} + + )} ); diff --git a/web-marketplace/src/components/organisms/ProjectCardsSection/ProjectCardsSection.tsx b/web-marketplace/src/components/organisms/ProjectCardsSection/ProjectCardsSection.tsx index 6dffc386f8..388f5d9acd 100644 --- a/web-marketplace/src/components/organisms/ProjectCardsSection/ProjectCardsSection.tsx +++ b/web-marketplace/src/components/organisms/ProjectCardsSection/ProjectCardsSection.tsx @@ -16,10 +16,10 @@ import { getProjectCardButtonMapping, getProjectCardPurchaseDetailsTitleMapping, } from 'lib/constants/shared.constants'; +import { NormalizeProject } from 'lib/normalizers/projects/normalizeProjectsWithMetadata'; import { getSoldOutProjectsQuery } from 'lib/queries/react-query/sanity/getSoldOutProjectsQuery/getSoldOutProjectsQuery'; import { useTracker } from 'lib/tracker/useTracker'; -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; import { getCreditsTooltip } from 'pages/Projects/AllProjects/utils/getCreditsTooltip'; import { getIsSoldOut } from 'pages/Projects/AllProjects/utils/getIsSoldOut'; import WithLoader from 'components/atoms/WithLoader'; @@ -31,7 +31,7 @@ import { useSectionStyles } from './ProjectCardsSection.styles'; import { ProjectCardOnButtonClickParams } from './ProjectCardsSection.types'; interface Props { - projects: ProjectWithOrderData[]; + projects: NormalizeProject[]; title?: string; body?: Maybe; titleAlign?: 'center' | 'left'; diff --git a/web-marketplace/src/components/organisms/ProjectCardsSection/ProjectCardsSection.types.ts b/web-marketplace/src/components/organisms/ProjectCardsSection/ProjectCardsSection.types.ts index ffded05963..545bd3a0b1 100644 --- a/web-marketplace/src/components/organisms/ProjectCardsSection/ProjectCardsSection.types.ts +++ b/web-marketplace/src/components/organisms/ProjectCardsSection/ProjectCardsSection.types.ts @@ -1,5 +1,5 @@ -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; +import { NormalizeProject } from 'lib/normalizers/projects/normalizeProjectsWithMetadata'; export type ProjectCardOnButtonClickParams = { - project: ProjectWithOrderData; + project: NormalizeProject; }; diff --git a/web-marketplace/src/components/organisms/SellOrdersActionsBar/SellOrdersActionsBar.tsx b/web-marketplace/src/components/organisms/SellOrdersActionsBar/SellOrdersActionsBar.tsx index 37b39e9571..96a570f23c 100644 --- a/web-marketplace/src/components/organisms/SellOrdersActionsBar/SellOrdersActionsBar.tsx +++ b/web-marketplace/src/components/organisms/SellOrdersActionsBar/SellOrdersActionsBar.tsx @@ -31,10 +31,10 @@ import { import { SellOrdersActionsBarCreatePostButton } from './SellOrdersActionsBar.CreatePostButton'; type Params = { - isBuyButtonDisabled: boolean; + isBuyButtonDisabled?: boolean; isCommunityCredit: boolean; onBookCallButtonClick: () => void; - onBuyButtonClick: () => void; + onBuyButtonClick?: () => void; onChainProjectId?: string | null; offChainProjectId?: string | null; projectName?: string; @@ -173,7 +173,7 @@ export const SellOrdersActionsBar = ({ {_(BOOK_CALL)} )} - {(!!onChainProjectId || !!onChainCreditClassId) && ( + {onBuyButtonClick && !!onChainProjectId && !!onChainCreditClassId && ( (null); - const [isBuyFlowStarted, setIsBuyFlowStarted] = useState(false); const { isKeplrMobileWeb } = useWallet(); + const onBuyButtonClick = useOnBuyButtonClick(); return ( { - setSelectedProject(project); - setIsBuyFlowStarted(true); + onBuyButtonClick({ + projectId: project?.id, + cardSellOrders: project?.cardSellOrders, + loading, + }); }} /> - ); } diff --git a/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.loader.ts b/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.loader.ts index 0953a746cc..91d03ede22 100644 --- a/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.loader.ts +++ b/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.loader.ts @@ -9,7 +9,6 @@ import { getSellOrdersExtendedQuery } from 'lib/queries/react-query/ecocredit/ma import { getProjectByOnChainIdQuery } from 'lib/queries/react-query/registry-server/graphql/getProjectByOnChainIdQuery/getProjectByOnChainIdQuery'; import { getProjectBySlugQuery } from 'lib/queries/react-query/registry-server/graphql/getProjectBySlugQuery/getProjectBySlugQuery'; import { getAllSanityCreditClassesQuery } from 'lib/queries/react-query/sanity/getAllCreditClassesQuery/getAllCreditClassesQuery'; -import { getAllSanityPrefinanceProjectsQuery } from 'lib/queries/react-query/sanity/getAllPrefinanceProjectsQuery/getAllPrefinanceProjectsQuery'; import { getAllProjectPageQuery } from 'lib/queries/react-query/sanity/getAllProjectPageQuery/getAllProjectPageQuery'; import { getFromCacheOrFetch } from 'lib/queries/react-query/utils/getFromCacheOrFetch'; @@ -33,10 +32,6 @@ export const projectDetailsLoader = // Queries const allProjectPageQuery = getAllProjectPageQuery({ sanityClient }); - const allSanityPrefinanceProjectsQuery = - getAllSanityPrefinanceProjectsQuery({ - sanityClient, - }); const allCreditClassesQuery = getAllSanityCreditClassesQuery({ sanityClient, }); @@ -89,10 +84,6 @@ export const projectDetailsLoader = query: allCreditClassesQuery, reactQueryClient: queryClient, }); - getFromCacheOrFetch({ - query: allSanityPrefinanceProjectsQuery, - reactQueryClient: queryClient, - }); getFromCacheOrFetch({ query: sellOrdersQuery, reactQueryClient: queryClient, diff --git a/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.tsx b/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.tsx index 00f1f6d139..1dd810f936 100644 --- a/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.tsx +++ b/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.tsx @@ -15,10 +15,6 @@ import InfoTooltip from 'web-components/src/components/tooltip/InfoTooltip'; import { Project } from 'generated/graphql'; import { Maybe } from 'graphql/jsutils/Maybe'; -import { - connectWalletModalAtom, - switchWalletModalAtom, -} from 'lib/atoms/modals.atoms'; import { useAuth } from 'lib/auth/auth'; import { onBtnClick } from 'lib/button'; import { @@ -41,6 +37,7 @@ import { useWallet } from 'lib/wallet/wallet'; import { CreateSellOrderFlow } from 'features/marketplace/CreateSellOrderFlow/CreateSellOrderFlow'; import { useCreateSellOrderData } from 'features/marketplace/CreateSellOrderFlow/hooks/useCreateSellOrderData'; +import { buyFromProjectIdAtom } from 'pages/BuyCredits/BuyCredits.atoms'; import { CREATE_POST_DISABLED_TOOLTIP_TEXT } from 'pages/Dashboard/MyProjects/MyProjects.constants'; import { SOLD_OUT_TOOLTIP } from 'pages/Projects/AllProjects/AllProjects.constants'; import { getPriceToDisplay } from 'pages/Projects/hooks/useProjectsSellOrders.utils'; @@ -52,6 +49,7 @@ import { ProjectStorySection } from 'components/organisms/ProjectStorySection/Pr import { SellOrdersActionsBar } from 'components/organisms/SellOrdersActionsBar/SellOrdersActionsBar'; import { AVG_PRICE_TOOLTIP_PROJECT } from 'components/organisms/SellOrdersActionsBar/SellOrdersActionsBar.constants'; import { useFetchPaginatedBatches } from 'hooks/batches/useFetchPaginatedBatches'; +import { useOnBuyButtonClick } from 'hooks/useOnBuyButtonClick'; import { useLedger } from '../../../ledger'; import { client as sanityClient } from '../../../lib/clients/sanity'; @@ -85,18 +83,9 @@ function ProjectDetails(): JSX.Element { const theme = useTheme(); const { projectId } = useParams(); const { ecocreditClient, dataClient } = useLedger(); - const setConnectWalletModal = useSetAtom(connectWalletModalAtom); - const setSwitchWalletModalAtom = useSetAtom(switchWalletModalAtom); - const { - activeWalletAddr, - isConnected, - isKeplrMobileWeb, - wallet, - loginDisabled, - } = useWallet(); + const { isConnected, isKeplrMobileWeb, wallet, loginDisabled } = useWallet(); const location = useLocation(); - const navigate = useNavigate(); const { activeAccount } = useAuth(); const [isCreatePostModalOpen, setIsCreatePostModalOpen] = useState(false); const [draftPost, setDraftPost] = useState< @@ -124,23 +113,14 @@ function ProjectDetails(): JSX.Element { getAllSanityCreditClassesQuery({ sanityClient, enabled: !!sanityClient }), ); - const [isBuyFlowStarted, setIsBuyFlowStarted] = useState(false); + const setBuyFromProjectId = useSetAtom(buyFromProjectIdAtom); const [isSellFlowStarted, setIsSellFlowStarted] = useState(false); - useEffect(() => { - // As soon as user connects to the right wallet address, - // we navigate to the buy page - if (isBuyFlowStarted && isConnected) { - navigate(`/project/${projectId}/buy`); - } - }, [isBuyFlowStarted, isConnected, navigate, projectId]); - const { sanityProject, loadingSanityProject, projectBySlug, loadingProjectBySlug, - projectByOnChainId, loadingProjectByOnChainId, offchainProjectByIdData, loadingOffchainProjectById, @@ -156,6 +136,7 @@ function ProjectDetails(): JSX.Element { } = useGetProject(); useNavigateToSlug(slug); + const onBuyButtonClick = useOnBuyButtonClick(); const element = document.getElementById(location.hash.substring(1)); useEffect(() => { @@ -318,7 +299,8 @@ function ProjectDetails(): JSX.Element { isConnected, orders: projectsWithOrderData[0]?.sellOrders, hideOtcCard: isCommunityCredit || !onChainProjectId, - setIsBuyFlowStarted, + setBuyFromProjectId, + projectId, }); const projectPrefinancing = sanityProject?.projectPrefinancing; @@ -384,30 +366,11 @@ function ProjectDetails(): JSX.Element { onBookCallButtonClick={onBookCallButtonClick} isAdmin={isAdmin} onBuyButtonClick={() => { - if ( - // some credits are available for fiat purchase - !loadingSanityProject && - !loadingBuySellOrders && - cardSellOrders.length > 0 - ) { - // so we can always go to the buy page, - // no matter if the user is logged in/connected to a wallet or not - navigate(`/project/${projectId}/buy`); - } else if (!loadingSanityProject && !loadingBuySellOrders) { - if (!activeWalletAddr) { - // no connected wallet address - setIsBuyFlowStarted(true); - setConnectWalletModal(atom => void (atom.open = true)); - } else { - if (isConnected) { - navigate(`/project/${projectId}/buy`); - } else { - // user logged in with web2 but not connected to the wallet address associated to his/er account - setIsBuyFlowStarted(true); - setSwitchWalletModalAtom(atom => void (atom.open = true)); - } - } - } + onBuyButtonClick({ + projectId, + loading: loadingSanityProject || loadingBuySellOrders, + cardSellOrders, + }); }} onChainProjectId={onChainProjectId} offChainProjectId={offChainProject?.id} diff --git a/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.utils.tsx b/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.utils.tsx index dfacf14607..580aaaa797 100644 --- a/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.utils.tsx +++ b/web-marketplace/src/components/templates/ProjectDetails/ProjectDetails.utils.tsx @@ -22,7 +22,6 @@ import { AllCreditClassQuery, AllProjectPageQuery, PrefinanceTimelineItem, - Project as SanityProject, } from 'generated/sanity-graphql'; import { UseStateSetter } from 'types/react/use-state'; import { onBtnClick } from 'lib/button'; @@ -251,7 +250,8 @@ type FormatOtcCardDataParams = { isConnected: boolean; orders?: UISellOrderInfo[]; hideOtcCard?: boolean; - setIsBuyFlowStarted: UseStateSetter; + setBuyFromProjectId: UseStateSetter; + projectId?: string; }; export const formatOtcCardData = ({ @@ -259,13 +259,14 @@ export const formatOtcCardData = ({ isConnected, orders = [], hideOtcCard, - setIsBuyFlowStarted, + setBuyFromProjectId, + projectId, }: FormatOtcCardDataParams): ActionCardProps | undefined => { const isNoteVisible = !isConnected || orders?.length > 0; const noteOnClick = (e: MouseEvent) => { - if (isConnected && orders?.length > 0) { + if (projectId && isConnected && orders?.length > 0) { e.preventDefault(); - setIsBuyFlowStarted(true); + setBuyFromProjectId(projectId); } }; @@ -294,22 +295,3 @@ export const formatTimelineDates = (item: PrefinanceTimelineItem) => `${formatDate(item.date, 'MMM YYYY')}${ item.endDate ? ` - ${formatDate(item.endDate, 'MMM YYYY')}` : '' }`; - -export const getCardSellOrders = ( - sanityFiatSellOrders: SanityProject['fiatSellOrders'], - sellOrders: UISellOrderInfo[], -) => - sanityFiatSellOrders - ?.map(fiatOrder => { - const sellOrder = sellOrders.find( - cryptoOrder => cryptoOrder.id.toString() === fiatOrder?.sellOrderId, - ); - if (sellOrder) { - return { - ...fiatOrder, - ...sellOrder, - }; - } - return null; - }) - .filter(Boolean) || []; diff --git a/web-marketplace/src/components/templates/ProjectDetails/hooks/useGetProject.ts b/web-marketplace/src/components/templates/ProjectDetails/hooks/useGetProject.ts index 122303b4e3..0b19fecd6d 100644 --- a/web-marketplace/src/components/templates/ProjectDetails/hooks/useGetProject.ts +++ b/web-marketplace/src/components/templates/ProjectDetails/hooks/useGetProject.ts @@ -1,4 +1,3 @@ -import { useMemo } from 'react'; import { useParams } from 'react-router-dom'; import { useApolloClient } from '@apollo/client'; import { useQuery } from '@tanstack/react-query'; @@ -9,22 +8,16 @@ import { getProjectByIdQuery as getOffChainProjectByIdQuery } from 'lib/queries/ import { getProjectByOnChainIdQuery } from 'lib/queries/react-query/registry-server/graphql/getProjectByOnChainIdQuery/getProjectByOnChainIdQuery'; import { getProjectBySlugQuery } from 'lib/queries/react-query/registry-server/graphql/getProjectBySlugQuery/getProjectBySlugQuery'; import { getProjectByIdQuery } from 'lib/queries/react-query/sanity/getProjectByIdQuery/getProjectByIdQuery'; -import { useWallet } from 'lib/wallet/wallet'; -import { useBuySellOrderData } from 'features/marketplace/BuySellOrderFlow/hooks/useBuySellOrderData'; +import { useBuySellOrderData } from 'hooks/useBuySellOrderData'; import { client as sanityClient } from '../../../../lib/clients/sanity'; -import { - getCardSellOrders, - getIsOnChainId, - getIsUuid, -} from '../ProjectDetails.utils'; +import { getIsOnChainId, getIsUuid } from '../ProjectDetails.utils'; export const useGetProject = () => { const { projectId } = useParams(); const graphqlClient = useApolloClient(); const { ecocreditClient } = useLedger(); - const { wallet } = useWallet(); // First, check if projectId is an on-chain project id // or an off-chain project UUID. @@ -114,18 +107,8 @@ export const useGetProject = () => { }), ); - const sellOrders = useMemo( - () => - (projectsWithOrderData?.[0]?.sellOrders || []).filter( - sellOrder => sellOrder.seller !== wallet?.address, - ), - [projectsWithOrderData, wallet?.address], - ); - - const cardSellOrders = useMemo( - () => getCardSellOrders(sanityProject?.fiatSellOrders, sellOrders), - [sanityProject?.fiatSellOrders, sellOrders], - ); + const sellOrders = projectsWithOrderData?.[0]?.filteredSellOrders || []; + const cardSellOrders = projectsWithOrderData?.[0]?.cardSellOrders || []; const slug = offchainProjectByIdData?.data?.projectById?.slug || diff --git a/web-marketplace/src/features/marketplace/BuySellOrderFlow/BuySellOrderFlow.constants.ts b/web-marketplace/src/features/marketplace/BuySellOrderFlow/BuySellOrderFlow.constants.ts deleted file mode 100644 index 7eae84d338..0000000000 --- a/web-marketplace/src/features/marketplace/BuySellOrderFlow/BuySellOrderFlow.constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { msg } from '@lingui/macro'; - -export const BUY_FLOW_TWITTER_TEXT = msg`I just purchased carbon credits on #RegenMarketplace with @regen_network. Let's work together to reduce our carbon footprint. Join me in investing in a regenerative future! `; diff --git a/web-marketplace/src/features/marketplace/BuySellOrderFlow/BuySellOrderFlow.tsx b/web-marketplace/src/features/marketplace/BuySellOrderFlow/BuySellOrderFlow.tsx deleted file mode 100644 index 79a73cfa52..0000000000 --- a/web-marketplace/src/features/marketplace/BuySellOrderFlow/BuySellOrderFlow.tsx +++ /dev/null @@ -1,328 +0,0 @@ -import { useEffect, useMemo, useRef, useState } from 'react'; -import { Location, useNavigate } from 'react-router-dom'; -import { DeliverTxResponse } from '@cosmjs/stargate'; -import { msg } from '@lingui/macro'; -import { useLingui } from '@lingui/react'; -import { useQuery } from '@tanstack/react-query'; -import { errorsMapping, findErrorByCodeEnum } from 'config/errors'; -import { useSetAtom } from 'jotai'; -import { getSocialItems } from 'utils/components/ShareSection/getSocialItems'; -import { REGEN_APP_PROJECT_URL } from 'utils/components/ShareSection/getSocialItems.constants'; - -import { CelebrateIcon } from 'web-components/src/components/icons/CelebrateIcon'; -import { ProcessingModal } from 'web-components/src/components/modal/ProcessingModal'; -import { TxErrorModal } from 'web-components/src/components/modal/TxErrorModal'; -import { Item } from 'web-components/src/components/modal/TxModal'; -import { TxSuccessfulModal } from 'web-components/src/components/modal/TxSuccessfulModal'; - -import { UseStateSetter } from 'types/react/use-state'; -import { switchWalletModalAtom } from 'lib/atoms/modals.atoms'; -import { getHashUrl } from 'lib/block-explorer'; -import { client } from 'lib/clients/sanity'; -import { - BLOCKCHAIN_RECORD, - CLOSE_BUTTON_TEXT, - PROCESSING_MODAL_BODY, - PROCESSING_MODAL_TITLE, - SEE_LESS, - SEE_MORE, - SHARE_TITLE, - TX_ERROR_MODAL_TITLE, - TX_MODAL_TITLE, -} from 'lib/constants/shared.constants'; -import { getBuyModalOptionsQuery } from 'lib/queries/react-query/sanity/getBuyModalOptionsQuery/getBuyModalOptionsQuery'; -import { Track } from 'lib/tracker/types'; -import { useWallet } from 'lib/wallet/wallet'; - -import useBuySellOrderSubmit from 'pages/Marketplace/Storefront/hooks/useBuySellOrderSubmit'; -import { useCheckSellOrderAvailabilty } from 'pages/Marketplace/Storefront/hooks/useCheckSellOrderAvailabilty'; -import { VIEW_ECOCREDITS } from 'pages/Projects/AllProjects/AllProjects.config'; -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; -import { normalizeToUISellOrderInfo } from 'pages/Projects/hooks/useProjectsSellOrders.utils'; -import { Link } from 'components/atoms'; -import { BuyCreditsModal, BuyCreditsValues } from 'components/organisms'; -import { BuyModalOptions } from 'components/organisms/BuyModalOptions/BuyModalOptions'; -import { useMsgClient } from 'hooks'; - -import { BUY_FLOW_TWITTER_TEXT } from './BuySellOrderFlow.constants'; -import { useFetchSellOrders } from './hooks/useFetchSellOrders'; -import { useSelectedProject } from './hooks/useSelectedProject'; - -type Props = { - isFlowStarted: boolean; - isCommunityCredit?: boolean; - setIsFlowStarted: UseStateSetter; - projects?: ProjectWithOrderData[] | null | undefined; - track?: Track; - location?: Location; -}; - -export const BuySellOrderFlow = ({ - projects, - isFlowStarted, - isCommunityCredit = false, - setIsFlowStarted, - track, - location, -}: Props): JSX.Element => { - /** - * ui management - */ - const { _ } = useLingui(); - const navigate = useNavigate(); - - // persistence for Tx details (orderId and amount) - const selectedSellOrderIdRef = useRef(); - const submittedQuantityRef = useRef(); - - // modals and display - const [isBuyModalOpen, setIsBuyModalOpen] = useState(false); - const [isBuyModalOptionsOpen, setIsBuyModalOptionsOpen] = useState(false); - const [isProcessingModalOpen, setIsProcessingModalOpen] = useState(false); - const [txModalTitle, setTxModalTitle] = useState(''); - const [txButtonTitle, setTxButtonTitle] = useState(''); - const [txModalHeader, setTxModalHeader] = useState(''); - const [cardItems, setCardItems] = useState(undefined); - const { sellOrders, refetchSellOrders } = useFetchSellOrders(); - const { isConnected, wallet, activeWalletAddr } = useWallet(); - const { data: buyModalOptionsContent } = useQuery( - getBuyModalOptionsQuery({ sanityClient: client }), - ); - const setSwitchWalletModalAtom = useSetAtom(switchWalletModalAtom); - const buyModalOptions = buyModalOptionsContent?.allBuyModalOptions[0]; - const buyModalOptionsFiltered = isCommunityCredit - ? { - ...buyModalOptions, - cards: buyModalOptions?.cards?.slice(1, buyModalOptions?.cards?.length), - } - : buyModalOptions; - - const closeBuyModal = (): void => { - setIsBuyModalOpen(false); - setIsFlowStarted(false); - }; - const closeProcessingModal = (): void => setIsProcessingModalOpen(false); - const handleTxModalClose = (): void => { - setCardItems(undefined); - setTxModalTitle(''); - setTxModalHeader(''); - setDeliverTxResponse(undefined); - setError(undefined); - setIsFlowStarted(false); - selectedSellOrderIdRef.current = undefined; - setSelectedProject(undefined); - }; - const onTxSuccessButtonClick = (): void => { - handleTxModalClose(); - navigate('/profile/portfolio'); - }; - - /** - * ledger msg hook setup - */ - const handleTxQueued = (): void => { - setIsProcessingModalOpen(true); - }; - const handleTxDelivered = async ( - _deliverTxResponse: DeliverTxResponse, - ): Promise => { - closeProcessingModal(); - closeBuyModal(); - selectedSellOrderIdRef.current = undefined; - }; - const handleError = (): void => { - closeProcessingModal(); - setTxModalTitle(_(msg`Buy Credits Error`)); - }; - - const { - signAndBroadcast, - setDeliverTxResponse, - deliverTxResponse, - error, - setError, - } = useMsgClient(handleTxQueued, handleTxDelivered, handleError); - - const accountAddress = wallet?.address; - const txHash = deliverTxResponse?.transactionHash; - const txHashUrl = getHashUrl(txHash); - const errorEnum = findErrorByCodeEnum({ errorCode: error }); - const ErrorIcon = errorsMapping[errorEnum].icon; - - /** - * data processing - */ - const { selectedProject, setSelectedProject, setSelectedProjectById } = - useSelectedProject({ projects }); - - const projectsSellOrdersIds = useMemo( - () => - projects && - projects - .map(project => project.sellOrders) - .flat() - .map(sellOrder => sellOrder.id), - [projects], - ); - - const _sellOrders = useMemo( - () => - sellOrders - ?.map(normalizeToUISellOrderInfo) - .filter(sellOrder => projectsSellOrdersIds?.includes(sellOrder.id)) - .filter(sellOrder => sellOrder.seller !== accountAddress), - [sellOrders, projectsSellOrdersIds, accountAddress], - ); - - const _project = useMemo( - () => - selectedProject && { - id: selectedProject?.id.toString() ?? '', - }, - [selectedProject], - ); - - /** - * Check the selected order availability on sellOrders refresh - */ - useCheckSellOrderAvailabilty({ - selectedSellOrderIdRef, - submittedQuantityRef, - setError, - sellOrders: _sellOrders, - setCardItems, - setTxModalHeader, - setTxModalTitle, - }); - - /** - * Submit hook setup - */ - const onSubmitCallback = ({ - creditCount, - sellOrderId, - }: BuyCreditsValues): void => { - selectedSellOrderIdRef.current = Number(sellOrderId); - submittedQuantityRef.current = creditCount; - }; - - const projectDisplayData = useMemo(() => { - if (!selectedProject || !selectedProject.id) return; - const projectId = selectedProject.id; - return { - id: projectId, - name: selectedProject.name ?? projectId, - }; - }, [selectedProject]); - - const shareUrl = REGEN_APP_PROJECT_URL + (selectedProject?.id ?? ''); - - const buySellOrderSubmit = useBuySellOrderSubmit({ - accountAddress, - project: projectDisplayData, - signAndBroadcast, - setCardItems, - setTxButtonTitle, - setTxModalHeader, - setTxModalTitle, - onBroadcast: () => setIsBuyModalOpen(false), - buttonTitle: VIEW_ECOCREDITS, - refetchSellOrders, - onSubmitCallback, - }); - - /** - * ui update effect - */ - useEffect(() => { - if (isFlowStarted && isConnected) { - refetchSellOrders(); - setIsBuyModalOpen(true); - } else if (isFlowStarted && !activeWalletAddr) { - setIsBuyModalOptionsOpen(true); - } else if (isFlowStarted && !isConnected) { - setSwitchWalletModalAtom(atom => { - atom.open = true; - atom.onClose = () => setIsFlowStarted(false); - }); - } - }, [ - isFlowStarted, - isConnected, - refetchSellOrders, - setSwitchWalletModalAtom, - setIsFlowStarted, - activeWalletAddr, - ]); - - return ( - <> - 1 ? setSelectedProjectById : undefined - } - isCommunityCredit={isCommunityCredit} - /> - { - setIsFlowStarted(false); - setIsBuyModalOptionsOpen(false); - }} - selectedProject={selectedProject} - track={track} - location={location} - /> - - } - socialItems={getSocialItems({ - twitter: { text: _(BUY_FLOW_TWITTER_TEXT), url: shareUrl }, - linkedIn: { url: shareUrl }, - })} - shareTitle={_(SHARE_TITLE)} - blockchainRecordText={_(BLOCKCHAIN_RECORD)} - /> - } - blockchainRecordText={_(BLOCKCHAIN_RECORD)} - /> - - ); -}; diff --git a/web-marketplace/src/features/marketplace/BuySellOrderFlow/hooks/useSelectedProject.tsx b/web-marketplace/src/features/marketplace/BuySellOrderFlow/hooks/useSelectedProject.tsx deleted file mode 100644 index 1ff2926c49..0000000000 --- a/web-marketplace/src/features/marketplace/BuySellOrderFlow/hooks/useSelectedProject.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { useEffect, useState } from 'react'; - -import { UseStateSetter } from 'types/react/use-state'; - -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; - -type Props = { - projects?: ProjectWithOrderData[] | null | undefined; -}; - -type ReponseType = { - selectedProject: ProjectWithOrderData | undefined; - setSelectedProject: UseStateSetter; - setSelectedProjectById: (projectId: string) => void | undefined; -}; - -export const useSelectedProject = ({ projects }: Props): ReponseType => { - const [selectedProject, setSelectedProject] = - useState(); - - useEffect(() => { - if (projects?.length === 1) setSelectedProject(projects[0]); - }, [projects]); - - const setSelectedProjectById = (projectId: string): void | undefined => { - if (!projects || projects.length <= 1) return; - const found = projects.find(project => project.id === projectId); - if (found) setSelectedProject(found); - }; - - return { - selectedProject, - setSelectedProject, - setSelectedProjectById, - }; -}; diff --git a/web-marketplace/src/features/marketplace/CreateSellOrderFlow/hooks/useCreateSellOrderData.tsx b/web-marketplace/src/features/marketplace/CreateSellOrderFlow/hooks/useCreateSellOrderData.tsx index d5dbaede8b..2123bb638f 100644 --- a/web-marketplace/src/features/marketplace/CreateSellOrderFlow/hooks/useCreateSellOrderData.tsx +++ b/web-marketplace/src/features/marketplace/CreateSellOrderFlow/hooks/useCreateSellOrderData.tsx @@ -6,12 +6,12 @@ type Props = { projectId: string; }; -type ReponseType = { +type ResponseType = { isSellFlowDisabled: boolean; credits: BatchInfoWithBalance[]; }; -export const useCreateSellOrderData = ({ projectId }: Props): ReponseType => { +export const useCreateSellOrderData = ({ projectId }: Props): ResponseType => { const { credits, isLoadingCredits } = useFetchEcocredits({}); const creditsForProject = credits?.filter( credit => credit.projectId === projectId, diff --git a/web-marketplace/src/hooks/projects/useProjectsWithOrders.ts b/web-marketplace/src/hooks/projects/useProjectsWithOrders.ts index bbcbb82a2c..10826a2796 100644 --- a/web-marketplace/src/hooks/projects/useProjectsWithOrders.ts +++ b/web-marketplace/src/hooks/projects/useProjectsWithOrders.ts @@ -17,6 +17,7 @@ import { getMetadataQuery } from 'lib/queries/react-query/registry-server/getMet import { getProjectByOnChainIdQuery } from 'lib/queries/react-query/registry-server/graphql/getProjectByOnChainIdQuery/getProjectByOnChainIdQuery'; import { getAllSanityCreditClassesQuery } from 'lib/queries/react-query/sanity/getAllCreditClassesQuery/getAllCreditClassesQuery'; import { getAllSanityPrefinanceProjectsQuery } from 'lib/queries/react-query/sanity/getAllPrefinanceProjectsQuery/getAllPrefinanceProjectsQuery'; +import { getProjectByIdQuery } from 'lib/queries/react-query/sanity/getProjectByIdQuery/getProjectByIdQuery'; import { useWallet } from 'lib/wallet/wallet'; import { UNREGISTERED_PATH } from 'pages/Projects/AllProjects/AllProjects.constants'; @@ -289,6 +290,24 @@ export function useProjectsWithOrders({ sortedProjects.map(project => project?.creditClassId), ); + // Sanity projects + const sanityProjectsResults = useQueries({ + queries: sortedProjects?.map(project => { + const id = project.slug || project.id; + return getProjectByIdQuery({ + id, + sanityClient, + enabled: !!sanityClient && !!id, + }); + }), + }); + const sanityProjects = sanityProjectsResults.map(res => { + return res.data?.allProject?.[0]; + }); + const sanityProjectsLoading = sanityProjectsResults.some( + res => res.isFetching, + ); + /* Final Normalization */ const projectsWithMetadata = useMemo( @@ -302,8 +321,9 @@ export function useProjectsWithOrders({ projectPagesMetadata, programAccounts, sanityCreditClassData: creditClassData, - prefinanceProjectsData, classesMetadata, + sanityProjects, + wallet, }), [ sortedProjects, @@ -311,8 +331,9 @@ export function useProjectsWithOrders({ projectPagesMetadata, programAccounts, creditClassData, - prefinanceProjectsData, classesMetadata, + sanityProjects, + wallet, ], ); @@ -331,8 +352,10 @@ export function useProjectsWithOrders({ isLoadingProjects || isLoadingProjectsByClass || isLoadingSellOrders || + !marketplaceClient || isLoadingSanityCreditClasses || isLoadingPrefinanceProjects || + sanityProjectsLoading || isLoadingProject || isClassesMetadataLoading || projectsMetadataLoading || diff --git a/web-marketplace/src/features/marketplace/BuySellOrderFlow/hooks/useBuySellOrderData.tsx b/web-marketplace/src/hooks/useBuySellOrderData.tsx similarity index 59% rename from web-marketplace/src/features/marketplace/BuySellOrderFlow/hooks/useBuySellOrderData.tsx rename to web-marketplace/src/hooks/useBuySellOrderData.tsx index 1796e8d499..120cb5d354 100644 --- a/web-marketplace/src/features/marketplace/BuySellOrderFlow/hooks/useBuySellOrderData.tsx +++ b/web-marketplace/src/hooks/useBuySellOrderData.tsx @@ -1,6 +1,5 @@ -import { useWallet } from 'lib/wallet/wallet'; +import { NormalizeProject } from 'lib/normalizers/projects/normalizeProjectsWithMetadata'; -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; import { useProjectsWithOrders } from 'hooks/projects/useProjectsWithOrders'; type Props = { @@ -8,33 +7,28 @@ type Props = { classId?: string; }; -type ReponseType = { +type ResponseType = { isBuyFlowDisabled: boolean; - projectsWithOrderData: ProjectWithOrderData[]; + projectsWithOrderData: NormalizeProject[]; loadingBuySellOrders: boolean; }; export const useBuySellOrderData = ({ projectId, classId, -}: Props): ReponseType => { - const { wallet } = useWallet(); - +}: Props): ResponseType => { const { projectsWithOrderData, loading: loadingProjects } = useProjectsWithOrders({ projectId, classId, enableOffchainProjectsQuery: false, + useCommunityProjects: true, }); - const sellOrdersAvailable = projectsWithOrderData[0]?.sellOrders.filter( - sellOrder => sellOrder.seller !== wallet?.address, - ); - const isBuyFlowDisabled = loadingProjects || projectsWithOrderData?.length === 0 || - sellOrdersAvailable?.length === 0; + projectsWithOrderData[0]?.filteredSellOrders?.length === 0; return { loadingBuySellOrders: loadingProjects, diff --git a/web-marketplace/src/hooks/useOnBuyButtonClick.ts b/web-marketplace/src/hooks/useOnBuyButtonClick.ts new file mode 100644 index 0000000000..9b01b4f92c --- /dev/null +++ b/web-marketplace/src/hooks/useOnBuyButtonClick.ts @@ -0,0 +1,76 @@ +import { useCallback, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useAtom, useSetAtom } from 'jotai'; + +import { + connectWalletModalAtom, + switchWalletModalAtom, +} from 'lib/atoms/modals.atoms'; +import { useWallet } from 'lib/wallet/wallet'; + +import { buyFromProjectIdAtom } from 'pages/BuyCredits/BuyCredits.atoms'; +import { CardSellOrder } from 'components/organisms/ChooseCreditsForm/ChooseCreditsForm.types'; + +type OnBuyButtonClickParams = { + projectId?: string; + loading: boolean; + cardSellOrders?: CardSellOrder[]; +}; +export const useOnBuyButtonClick = () => { + const navigate = useNavigate(); + + const setConnectWalletModal = useSetAtom(connectWalletModalAtom); + const setSwitchWalletModalAtom = useSetAtom(switchWalletModalAtom); + const [buyFromProjectId, setBuyFromProjectIdAtom] = + useAtom(buyFromProjectIdAtom); + const { activeWalletAddr, isConnected } = useWallet(); + + const onBuyButtonClick = useCallback( + ({ projectId, loading, cardSellOrders }: OnBuyButtonClickParams) => { + if (loading || !projectId) return; + + if ( + // some credits are available for fiat purchase + cardSellOrders && + cardSellOrders.length > 0 + ) { + // so we can always go to the buy page, + // no matter if the user is logged in/connected to a wallet or not + navigate(`/project/${projectId}/buy`); + } else { + if (!activeWalletAddr) { + // no connected wallet address + setBuyFromProjectIdAtom(projectId); + setConnectWalletModal(atom => void (atom.open = true)); + } else { + if (isConnected) { + navigate(`/project/${projectId}/buy`); + } else { + // user logged in with web2 but not connected to the wallet address associated to his/er account + setBuyFromProjectIdAtom(projectId); + setSwitchWalletModalAtom(atom => void (atom.open = true)); + } + } + } + }, + [ + activeWalletAddr, + isConnected, + navigate, + setBuyFromProjectIdAtom, + setConnectWalletModal, + setSwitchWalletModalAtom, + ], + ); + + useEffect(() => { + // As soon as user connects to the right wallet address, + // we navigate to the buy page + if (buyFromProjectId && isConnected) { + navigate(`/project/${buyFromProjectId}/buy`); + setBuyFromProjectIdAtom(''); + } + }, [buyFromProjectId, isConnected, navigate, setBuyFromProjectIdAtom]); + + return onBuyButtonClick; +}; diff --git a/web-marketplace/src/lib/normalizers/projects/normalizeProjectsWithMetadata.ts b/web-marketplace/src/lib/normalizers/projects/normalizeProjectsWithMetadata.ts index 9df47712a8..96a6ee5574 100644 --- a/web-marketplace/src/lib/normalizers/projects/normalizeProjectsWithMetadata.ts +++ b/web-marketplace/src/lib/normalizers/projects/normalizeProjectsWithMetadata.ts @@ -11,8 +11,9 @@ import { } from 'generated/graphql'; import { AllCreditClassQuery, - AllPrefinanceProjectQuery, CreditClass, + Project as SanityProject, + ProjectByIdQuery, ProjectPrefinancing, } from 'generated/sanity-graphql'; import { @@ -20,9 +21,14 @@ import { CreditClassMetadataLD, ProjectPageMetadataLD, } from 'lib/db/types/json-ld'; +import { Wallet } from 'lib/wallet/wallet'; -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; +import { + ProjectWithOrderData, + UISellOrderInfo, +} from 'pages/Projects/AllProjects/AllProjects.types'; import { getPriceToDisplay } from 'pages/Projects/hooks/useProjectsSellOrders.utils'; +import { CardSellOrder } from 'components/organisms/ChooseCreditsForm/ChooseCreditsForm.types'; import { getDisplayAccount } from 'components/templates/ProjectDetails/ProjectDetails.utils'; interface NormalizeProjectsWithOrderDataParams { @@ -32,8 +38,9 @@ interface NormalizeProjectsWithOrderDataParams { projectPagesMetadata?: ProjectPageMetadataLD[]; programAccounts?: Maybe[]; sanityCreditClassData?: AllCreditClassQuery; - prefinanceProjectsData?: AllPrefinanceProjectQuery; classesMetadata?: (CreditClassMetadataLD | undefined)[]; + sanityProjects?: (ProjectByIdQuery['allProject'][0] | undefined)[]; + wallet?: Wallet; } export const normalizeProjectsWithMetadata = ({ @@ -43,8 +50,9 @@ export const normalizeProjectsWithMetadata = ({ projectPagesMetadata, programAccounts, classesMetadata, - prefinanceProjectsData, -}: NormalizeProjectsWithOrderDataParams): ProjectWithOrderData[] => { + sanityProjects, + wallet, +}: NormalizeProjectsWithOrderDataParams): NormalizeProject[] => { const projectsWithMetadata = projectsWithOrderData?.map( (projectWithOrderData: ProjectWithOrderData, index) => { const projectMetadata = projectsMetadata?.[index]; @@ -52,13 +60,8 @@ export const normalizeProjectsWithMetadata = ({ const projectPageMetadata = projectPagesMetadata?.[index]; const programAccount = programAccounts?.[index]; const offChainProject = offChainProjects?.[index]; + const sanityProject = sanityProjects?.[index]; const sanityClass = projectWithOrderData.sanityCreditClassData; - const prefinanceProject = prefinanceProjectsData?.allProject?.find( - project => - project.projectId === projectWithOrderData.offChainId || - project.projectId === projectWithOrderData.id || // on-chain id - project.projectId === projectWithOrderData.slug, - ); return normalizeProjectWithMetadata({ offChainProject, @@ -68,7 +71,8 @@ export const normalizeProjectsWithMetadata = ({ programAccount, classMetadata, sanityClass, - projectPrefinancing: prefinanceProject?.projectPrefinancing, + sanityProject, + wallet, }); }, ); @@ -93,6 +97,8 @@ interface NormalizeProjectWithMetadataParams { | 'stripePaymentLink' > >; + sanityProject?: ProjectByIdQuery['allProject'][0] | undefined; + wallet?: Wallet; } export type NormalizeProject = ProjectWithOrderData & { @@ -106,7 +112,8 @@ export type NormalizeProject = ProjectWithOrderData & { place?: string; program?: Maybe; area?: number; - projectPrefinancing?: ProjectPrefinancing; + cardSellOrders?: Array; + filteredSellOrders?: Array; }; export const normalizeProjectWithMetadata = ({ offChainProject, @@ -116,7 +123,9 @@ export const normalizeProjectWithMetadata = ({ programAccount, classMetadata, sanityClass, + sanityProject, projectPrefinancing, + wallet, }: NormalizeProjectWithMetadataParams): NormalizeProject => { const creditClassImage = getClassImageWithProjectDefault({ metadata: classMetadata, @@ -129,6 +138,18 @@ export const normalizeProjectWithMetadata = ({ const projectId = projectWithOrderData?.id || offChainProject?.id; + const _projectPrefinancing = + projectPrefinancing || sanityProject?.projectPrefinancing; + + const filteredSellOrders = (projectWithOrderData?.sellOrders || []).filter( + sellOrder => sellOrder.seller !== wallet?.address, + ); + + const cardSellOrders = getCardSellOrders( + sanityProject?.fiatSellOrders, + filteredSellOrders, + ); + return { ...projectWithOrderData, id: projectId, @@ -160,17 +181,38 @@ export const normalizeProjectWithMetadata = ({ projectWithOrderData?.areaUnit || '', projectPrefinancing: { - ...projectPrefinancing, - price: projectPrefinancing?.price + ..._projectPrefinancing, + price: _projectPrefinancing?.price ? getPriceToDisplay({ - price: projectPrefinancing?.price, + price: _projectPrefinancing?.price, }) : undefined, - estimatedIssuance: projectPrefinancing?.estimatedIssuance + estimatedIssuance: _projectPrefinancing?.estimatedIssuance ? formatNumber({ - num: projectPrefinancing?.estimatedIssuance, + num: _projectPrefinancing?.estimatedIssuance, }) : undefined, }, + cardSellOrders, + filteredSellOrders, } as NormalizeProject; }; + +const getCardSellOrders = ( + sanityFiatSellOrders: SanityProject['fiatSellOrders'], + sellOrders: UISellOrderInfo[], +) => + sanityFiatSellOrders + ?.map(fiatOrder => { + const sellOrder = sellOrders.find( + cryptoOrder => cryptoOrder.id.toString() === fiatOrder?.sellOrderId, + ); + if (sellOrder) { + return { + ...fiatOrder, + ...sellOrder, + }; + } + return null; + }) + .filter(Boolean) || []; diff --git a/web-marketplace/src/pages/BuyCredits/BuyCredits.atoms.ts b/web-marketplace/src/pages/BuyCredits/BuyCredits.atoms.ts index 8637803c84..94b0b8d652 100644 --- a/web-marketplace/src/pages/BuyCredits/BuyCredits.atoms.ts +++ b/web-marketplace/src/pages/BuyCredits/BuyCredits.atoms.ts @@ -1,3 +1,4 @@ import { atom } from 'jotai'; export const paymentOptionCryptoClickedAtom = atom(false); +export const buyFromProjectIdAtom = atom(''); diff --git a/web-marketplace/src/pages/BuyCredits/BuyCredits.tsx b/web-marketplace/src/pages/BuyCredits/BuyCredits.tsx index 2c41877b4a..946847c873 100644 --- a/web-marketplace/src/pages/BuyCredits/BuyCredits.tsx +++ b/web-marketplace/src/pages/BuyCredits/BuyCredits.tsx @@ -102,7 +102,7 @@ export const BuyCredits = () => { paymentOption={paymentOption} retiring={retiring} setRetiring={setRetiring} - cardSellOrders={cardSellOrders as CardSellOrder[]} + cardSellOrders={cardSellOrders} cryptoSellOrders={sellOrders} creditTypeAbbrev={creditClassOnChain?.class?.creditTypeAbbrev} projectHref={`/project/${ diff --git a/web-marketplace/src/pages/CreditClassDetails/CreditClassDetails.Projects.tsx b/web-marketplace/src/pages/CreditClassDetails/CreditClassDetails.Projects.tsx index 8585332f74..02f9797db6 100644 --- a/web-marketplace/src/pages/CreditClassDetails/CreditClassDetails.Projects.tsx +++ b/web-marketplace/src/pages/CreditClassDetails/CreditClassDetails.Projects.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import { msg } from '@lingui/macro'; import { useLingui } from '@lingui/react'; import Box from '@mui/material/Box'; @@ -6,10 +6,9 @@ import cx from 'classnames'; import { useWallet } from 'lib/wallet/wallet'; -import { BuySellOrderFlow } from 'features/marketplace/BuySellOrderFlow/BuySellOrderFlow'; -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; import { ProjectCardsSection } from 'components/organisms/ProjectCardsSection/ProjectCardsSection'; import { useProjectsWithOrders } from 'hooks/projects/useProjectsWithOrders'; +import { useOnBuyButtonClick } from 'hooks/useOnBuyButtonClick'; interface Props { classId: string; @@ -23,11 +22,9 @@ function ProjectsSection({ classId }: Props): JSX.Element { enableOffchainProjectsQuery: false, }); - const [selectedProject, setSelectedProject] = - useState(null); - const [isBuyFlowStarted, setIsBuyFlowStarted] = useState(false); const { isKeplrMobileWeb } = useWallet(); const hasProjects = projectsWithOrderData.length > 0; + const onBuyButtonClick = useOnBuyButtonClick(); return ( <> @@ -44,15 +41,13 @@ function ProjectsSection({ classId }: Props): JSX.Element { projects={projectsWithOrderData} loading={loading} onButtonClick={({ project }) => { - setSelectedProject(project); - setIsBuyFlowStarted(true); + onBuyButtonClick({ + projectId: project?.id, + cardSellOrders: project?.cardSellOrders, + loading, + }); }} /> - )} diff --git a/web-marketplace/src/pages/CreditClassDetails/CreditClassDetails.tsx b/web-marketplace/src/pages/CreditClassDetails/CreditClassDetails.tsx index 07074a2d3d..2feefc16b7 100644 --- a/web-marketplace/src/pages/CreditClassDetails/CreditClassDetails.tsx +++ b/web-marketplace/src/pages/CreditClassDetails/CreditClassDetails.tsx @@ -5,45 +5,34 @@ import { NormalizedCacheObject, useApolloClient, } from '@apollo/client'; -import { useLingui } from '@lingui/react'; import { useQueries, useQuery } from '@tanstack/react-query'; -import { useSetAtom } from 'jotai'; import { Account } from 'web-components/src/components/user/UserInfo'; import { useCreditClassByUriQuery } from 'generated/graphql'; import { useAllCreditClassQuery } from 'generated/sanity-graphql'; -import { - connectWalletModalAtom, - switchWalletModalAtom, -} from 'lib/atoms/modals.atoms'; import { openLink } from 'lib/button'; import { client } from 'lib/clients/sanity'; import { CreditClassMetadataLD } from 'lib/db/types/json-ld'; import { queryClassIssuers } from 'lib/ecocredit/api'; import { onChainClassRegExp } from 'lib/ledger'; -import { getSimplePriceQuery } from 'lib/queries/react-query/coingecko/simplePrice/simplePriceQuery'; import { getClassQuery } from 'lib/queries/react-query/ecocredit/getClassQuery/getClassQuery'; import { getCsrfTokenQuery } from 'lib/queries/react-query/registry-server/getCsrfTokenQuery/getCsrfTokenQuery'; import { getMetadataQuery } from 'lib/queries/react-query/registry-server/getMetadataQuery/getMetadataQuery'; import { getAccountByAddrQuery } from 'lib/queries/react-query/registry-server/graphql/getAccountByAddrQuery/getAccountByAddrQuery'; import { getCreditClassByOnChainIdQuery } from 'lib/queries/react-query/registry-server/graphql/getCreditClassByOnChainIdQuery/getCreditClassByOnChainIdQuery'; import { getBuyModalOptionsQuery } from 'lib/queries/react-query/sanity/getBuyModalOptionsQuery/getBuyModalOptionsQuery'; -import { useWallet } from 'lib/wallet/wallet'; -import { BuySellOrderFlow } from 'features/marketplace/BuySellOrderFlow/BuySellOrderFlow'; -import { useBuySellOrderData } from 'features/marketplace/BuySellOrderFlow/hooks/useBuySellOrderData'; import { CreateSellOrderFlow } from 'features/marketplace/CreateSellOrderFlow/CreateSellOrderFlow'; import { useCreateSellOrderData } from 'features/marketplace/CreateSellOrderFlow/hooks/useCreateSellOrderData'; import useImpact from 'pages/CreditClassDetails/hooks/useImpact'; import { getDisplayAccountOrAddress } from 'components/organisms/DetailsSection/DetailsSection.utils'; import { SellOrdersActionsBar } from 'components/organisms/SellOrdersActionsBar/SellOrdersActionsBar'; -import { AVG_PRICE_TOOLTIP_CREDIT_CLASS } from 'components/organisms/SellOrdersActionsBar/SellOrdersActionsBar.constants'; import { getDisplayAccount } from 'components/templates/ProjectDetails/ProjectDetails.utils'; +import { useBuySellOrderData } from 'hooks/useBuySellOrderData'; import { useLedger } from '../../ledger'; import { - getCreditClassAvgPricePerTonLabel, getProjectNameFromProjectsData, parseCreditClassVersion, } from './CreditClassDetails.utils'; @@ -57,17 +46,12 @@ interface CreditDetailsProps { function CreditClassDetails({ isLandSteward, }: CreditDetailsProps): JSX.Element { - const { _ } = useLingui(); - const { activeWalletAddr, isConnected } = useWallet(); const { dataClient, ecocreditClient } = useLedger(); const { creditClassId } = useParams(); const graphqlClient = useApolloClient() as ApolloClient; const [issuers, setIssuers] = useState(undefined); - const [isBuyFlowStarted, setIsBuyFlowStarted] = useState(false); const [isSellFlowStarted, setIsSellFlowStarted] = useState(false); - const setConnectWalletModal = useSetAtom(connectWalletModalAtom); - const setSwitchWalletModalAtom = useSetAtom(switchWalletModalAtom); const { data: buyModalOptionsContent } = useQuery( getBuyModalOptionsQuery({ sanityClient: client }), @@ -133,7 +117,7 @@ function CreditClassDetails({ const dbCreditClassByOnChainId = dbDataByOnChainId?.creditClassByOnChainId; const dbCreditClassByUri = dbDataByUri?.creditClassByUri; - const { isBuyFlowDisabled, projectsWithOrderData } = useBuySellOrderData({ + const { projectsWithOrderData } = useBuySellOrderData({ classId: creditClassId, }); @@ -153,13 +137,6 @@ function CreditClassDetails({ })); }, [credits, projectsWithOrderData]); - const simplePrice = useQuery(getSimplePriceQuery({})); - - const avgPricePerTonLabel = getCreditClassAvgPricePerTonLabel({ - geckoPrices: simplePrice.data, - projectsWithOrderData, - }); - const onBookCallButtonClick = () => openLink(scheduleCallLink, true); const impact = useImpact({ offChainCoBenefitsIRIs, @@ -240,30 +217,8 @@ function CreditClassDetails({ /> )} { - if (!activeWalletAddr) { - setConnectWalletModal(atom => void (atom.open = true)); - } else { - if (isConnected) { - setIsBuyFlowStarted(true); - } else { - setSwitchWalletModalAtom(atom => void (atom.open = true)); - } - } - }} - onChainCreditClassId={onChainClass?.id} - creditClassName={metadata?.['schema:name']} - avgPricePerTonLabel={avgPricePerTonLabel} - avgPricePerTonTooltip={_(AVG_PRICE_TOOLTIP_CREDIT_CLASS)} - /> - 0, - }), + // Sanity projects + const sanityProjectsResults = useQueries({ + queries: + onlyOffChainProjects?.map(project => { + const id = project?.slug || project?.id; + return getProjectByIdQuery({ + id, + sanityClient, + enabled: !!sanityClient && !!id, + }); + }) || [], + }); + const sanityProjects = sanityProjectsResults.map(res => { + return res.data?.allProject?.[0]; + }); + const sanityProjectsLoading = sanityProjectsResults.some( + res => res.isLoading, ); const onlyOffChainProjectsWithData = - onlyOffChainProjects?.map(project => { - const prefinanceProject = prefinanceProjectsData?.allProject?.find( - sanityProject => - sanityProject.projectId === project?.id || - sanityProject.projectId === project?.slug, - ); + onlyOffChainProjects?.map((project, index) => { + const sanityProject = sanityProjects?.[index]; return { offChain: true, @@ -116,7 +117,7 @@ export const useFetchProjectByAdmin = ({ project?.metadata?.['regen:creditClassId'] ?? '', }), - projectPrefinancing: prefinanceProject?.projectPrefinancing, + sanityProject, }), }; }) ?? []; @@ -134,6 +135,6 @@ export const useFetchProjectByAdmin = ({ isOnChainProjectsLoading || isProjectsMetadataLoading || isClassesMetadataLoading || - isLoadingPrefinanceProjects, + sanityProjectsLoading, }; }; diff --git a/web-marketplace/src/pages/Dashboard/MyProjects/hooks/useFetchProjectsWithOrders.tsx b/web-marketplace/src/pages/Dashboard/MyProjects/hooks/useFetchProjectsWithOrders.tsx index b362e524a1..eb71a2d3bf 100644 --- a/web-marketplace/src/pages/Dashboard/MyProjects/hooks/useFetchProjectsWithOrders.tsx +++ b/web-marketplace/src/pages/Dashboard/MyProjects/hooks/useFetchProjectsWithOrders.tsx @@ -1,12 +1,14 @@ import { ProjectInfo } from '@regen-network/api/lib/generated/regen/ecocredit/v1/query'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useQueries, useQuery, useQueryClient } from '@tanstack/react-query'; import { Maybe, ProjectFieldsFragment } from 'generated/graphql'; import { AllCreditClassQuery } from 'generated/sanity-graphql'; import { useLedger } from 'ledger'; +import { client as sanityClient } from 'lib/clients/sanity'; import { normalizeProjectsWithMetadata } from 'lib/normalizers/projects/normalizeProjectsWithMetadata'; import { normalizeProjectsWithOrderData } from 'lib/normalizers/projects/normalizeProjectsWithOrderData'; import { getSellOrdersExtendedQuery } from 'lib/queries/react-query/ecocredit/marketplace/getSellOrdersExtendedQuery/getSellOrdersExtendedQuery'; +import { getProjectByIdQuery } from 'lib/queries/react-query/sanity/getProjectByIdQuery/getProjectByIdQuery'; import { useWallet } from 'lib/wallet/wallet'; import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; @@ -73,6 +75,21 @@ export const useFetchProjectsWithOrders = ({ project => project?.creditClassByCreditClassId?.accountByRegistryId, ); + // Sanity projects + const sanityProjectsResults = useQueries({ + queries: projectsWithOrderData?.map(project => { + const id = project.slug || project.id; + return getProjectByIdQuery({ + id, + sanityClient, + enabled: !!sanityClient && !!id, + }); + }), + }); + const sanityProjects = sanityProjectsResults.map(res => { + return res.data?.allProject?.[0]; + }); + /* Final Normalization */ const projectsWithMetadata = normalizeProjectsWithMetadata({ offChainProjects: orderedOffChainProjects, @@ -81,6 +98,8 @@ export const useFetchProjectsWithOrders = ({ projectPagesMetadata, programAccounts, classesMetadata, + sanityProjects, + wallet, }); return { diff --git a/web-marketplace/src/pages/EcocreditsByAccount/CreditClassTab/CreditClassTab.tsx b/web-marketplace/src/pages/EcocreditsByAccount/CreditClassTab/CreditClassTab.tsx index 929e5add42..e146f9e595 100644 --- a/web-marketplace/src/pages/EcocreditsByAccount/CreditClassTab/CreditClassTab.tsx +++ b/web-marketplace/src/pages/EcocreditsByAccount/CreditClassTab/CreditClassTab.tsx @@ -1,31 +1,22 @@ -import { useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { useLingui } from '@lingui/react'; import { Grid } from '@mui/material'; -import CurrentCreditsIcon from 'web-components/src/components/icons/CurrentCreditsIcon'; import { CreditClassGridCard } from 'web-components/src/components/molecules/CreditClassGridCard/CreditClassGridCard'; import { LinkComponentType } from 'web-components/src/types/shared/linkComponentType'; import { getProjectCardBodyTextMapping } from 'lib/constants/shared.constants'; import { useWallet } from 'lib/wallet/wallet'; -import { BuySellOrderFlow } from 'features/marketplace/BuySellOrderFlow/BuySellOrderFlow'; -import { useBuySellOrderData } from 'features/marketplace/BuySellOrderFlow/hooks/useBuySellOrderData'; import { Link } from 'components/atoms'; import WithLoader from 'components/atoms/WithLoader'; import { useFetchCreditClassesWithOrder } from 'hooks/classes/useFetchCreditClassesWithOrder'; import { useProfileData } from '../hooks/useProfileData'; -import { ACCOUNT_CREDIT_CLASS_BUTTON } from './CreditClassTab.constants'; export const CreditClassTab = () => { const { _ } = useLingui(); - const [isBuyFlowStarted, setIsBuyFlowStarted] = useState(false); - const [creditClassId, setCreditClassId] = useState(); const { wallet } = useWallet(); - const { projectsWithOrderData } = useBuySellOrderData({ - classId: creditClassId, - }); const { address } = useProfileData(); const { creditClasses, isLoadingCreditClasses } = useFetchCreditClassesWithOrder({ @@ -46,17 +37,6 @@ export const CreditClassTab = () => { , - onClick: () => { - setCreditClassId(creditClass.id); - setIsBuyFlowStarted(true); - }, - disabled: - (creditClass.purchaseInfo?.sellInfo - ?.creditsAvailableForUser ?? 0) === 0, - }} href={`/credit-classes/${creditClass.id}`} LinkComponent={Link as LinkComponentType} /> @@ -64,11 +44,6 @@ export const CreditClassTab = () => { ))} - ); }; diff --git a/web-marketplace/src/pages/EcocreditsByAccount/ProjectsTab/ProjectsTab.tsx b/web-marketplace/src/pages/EcocreditsByAccount/ProjectsTab/ProjectsTab.tsx index edb82576c1..20676650d9 100644 --- a/web-marketplace/src/pages/EcocreditsByAccount/ProjectsTab/ProjectsTab.tsx +++ b/web-marketplace/src/pages/EcocreditsByAccount/ProjectsTab/ProjectsTab.tsx @@ -1,17 +1,21 @@ -import { useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { useLingui } from '@lingui/react'; import { Grid } from '@mui/material'; import ProjectCard from 'web-components/src/components/cards/ProjectCard'; +import { + getProjectCardBodyTextMapping, + getProjectCardButtonMapping, + getProjectCardPurchaseDetailsTitleMapping, +} from 'lib/constants/shared.constants'; import { API_URI, IMAGE_STORAGE_BASE_URL } from 'lib/env'; import { useTracker } from 'lib/tracker/useTracker'; -import { BuySellOrderFlow } from 'features/marketplace/BuySellOrderFlow/BuySellOrderFlow'; import { useFetchProjectByAdmin } from 'pages/Dashboard/MyProjects/hooks/useFetchProjectsByAdmin'; -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; import WithLoader from 'components/atoms/WithLoader'; +import { useOnBuyButtonClick } from 'hooks/useOnBuyButtonClick'; import { useProfileData } from '../hooks/useProfileData'; import { getDefaultProject } from './ProjectsTab.constants'; @@ -29,9 +33,13 @@ const ProjectsTab = (): JSX.Element => { adminAddress: address, }); - const [selectedProject, setSelectedProject] = - useState(null); - const [isBuyFlowStarted, setIsBuyFlowStarted] = useState(false); + const buttons = useMemo(() => getProjectCardButtonMapping(_), [_]); + const bodyTexts = useMemo(() => getProjectCardBodyTextMapping(_), [_]); + const purchaseDetailsTitles = useMemo( + () => getProjectCardPurchaseDetailsTitleMapping(_), + [_], + ); + const onBuyButtonClick = useOnBuyButtonClick(); return ( <> @@ -42,29 +50,28 @@ const ProjectsTab = (): JSX.Element => { project.href && navigate(project.href)} track={track} pathname={location.pathname} imageStorageBaseUrl={IMAGE_STORAGE_BASE_URL} apiServerUrl={API_URI} onButtonClick={() => { - setSelectedProject(project as ProjectWithOrderData); - setIsBuyFlowStarted(true); + onBuyButtonClick({ + projectId: project?.id, + cardSellOrders: project?.cardSellOrders, + loading: isLoadingAdminProjects, + }); }} + buttons={buttons} + bodyTexts={bodyTexts} + purchaseDetailsTitles={purchaseDetailsTitles} /> ); })} - ); }; diff --git a/web-marketplace/src/pages/Home/Home.FeaturedProjects.tsx b/web-marketplace/src/pages/Home/Home.FeaturedProjects.tsx index 64708430a6..45a6d1ad45 100644 --- a/web-marketplace/src/pages/Home/Home.FeaturedProjects.tsx +++ b/web-marketplace/src/pages/Home/Home.FeaturedProjects.tsx @@ -1,4 +1,3 @@ -import { useState } from 'react'; import { Link } from 'react-router-dom'; import { Trans } from '@lingui/macro'; import { Box } from '@mui/material'; @@ -11,9 +10,8 @@ import { Scalars, } from 'generated/sanity-graphql'; -import { BuySellOrderFlow } from 'features/marketplace/BuySellOrderFlow/BuySellOrderFlow'; -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; import { ProjectCardsSection } from 'components/organisms/ProjectCardsSection/ProjectCardsSection'; +import { useOnBuyButtonClick } from 'hooks/useOnBuyButtonClick'; import { useFeaturedProjects } from './hooks/useFeaturedProjects'; @@ -32,9 +30,8 @@ export function FeaturedProjects({ String(project?.projectId), ); const { featuredProjects, loading } = useFeaturedProjects({ pinnedIds }); - const [selectedProject, setSelectedProject] = - useState(null); - const [isBuyFlowStarted, setIsBuyFlowStarted] = useState(false); + const onBuyButtonClick = useOnBuyButtonClick(); + return (
{ - setSelectedProject(project); - setIsBuyFlowStarted(true); + onBuyButtonClick({ + projectId: project?.id, + cardSellOrders: project?.cardSellOrders, + loading, + }); }} loading={loading} /> @@ -54,11 +54,6 @@ export function FeaturedProjects({ -
); } diff --git a/web-marketplace/src/pages/Home/hooks/useFeaturedProjects.ts b/web-marketplace/src/pages/Home/hooks/useFeaturedProjects.ts index a155989901..617c82db24 100644 --- a/web-marketplace/src/pages/Home/hooks/useFeaturedProjects.ts +++ b/web-marketplace/src/pages/Home/hooks/useFeaturedProjects.ts @@ -1,4 +1,5 @@ -import { ProjectWithOrderData } from 'pages/Projects/AllProjects/AllProjects.types'; +import { NormalizeProject } from 'lib/normalizers/projects/normalizeProjectsWithMetadata'; + import { useProjectsWithOrders } from 'hooks/projects/useProjectsWithOrders'; import { FEATURE_PROJECTS_COUNT, PROJECTS_SORT } from '../Home.constants'; @@ -8,7 +9,7 @@ type Props = { }; export function useFeaturedProjects({ pinnedIds }: Props): { - featuredProjects: ProjectWithOrderData[]; + featuredProjects: NormalizeProject[]; loading: boolean; } { // get normalized projects with sell order data diff --git a/web-marketplace/src/features/marketplace/BuySellOrderFlow/hooks/useFetchSellOrders.ts b/web-marketplace/src/pages/Marketplace/Storefront/hooks/useFetchSellOrders.ts similarity index 100% rename from web-marketplace/src/features/marketplace/BuySellOrderFlow/hooks/useFetchSellOrders.ts rename to web-marketplace/src/pages/Marketplace/Storefront/hooks/useFetchSellOrders.ts diff --git a/web-marketplace/src/pages/Marketplace/Storefront/hooks/useNormalizedSellOrders.tsx b/web-marketplace/src/pages/Marketplace/Storefront/hooks/useNormalizedSellOrders.tsx index da5c650022..33004d6153 100644 --- a/web-marketplace/src/pages/Marketplace/Storefront/hooks/useNormalizedSellOrders.tsx +++ b/web-marketplace/src/pages/Marketplace/Storefront/hooks/useNormalizedSellOrders.tsx @@ -15,7 +15,6 @@ import { getProjectsQuery } from 'lib/queries/react-query/ecocredit/getProjectsQ import { getMetadataQuery } from 'lib/queries/react-query/registry-server/getMetadataQuery/getMetadataQuery'; import { getAllSanityCreditClassesQuery } from 'lib/queries/react-query/sanity/getAllCreditClassesQuery/getAllCreditClassesQuery'; -import { useFetchSellOrders } from 'features/marketplace/BuySellOrderFlow/hooks/useFetchSellOrders'; import { UISellOrderInfo } from 'pages/Projects/AllProjects/AllProjects.types'; import { normalizeToUISellOrderInfo } from 'pages/Projects/hooks/useProjectsSellOrders.utils'; import { useClassesWithMetadata } from 'hooks/classes/useClassesWithMetadata'; @@ -26,6 +25,7 @@ import { normalizeSellOrders, } from '../Storefront.normalizer'; import { NormalizedSellOrder } from '../Storefront.types'; +import { useFetchSellOrders } from './useFetchSellOrders'; import { useSortedSellOrders } from './useSortedSellOrders'; type ResponseType = { diff --git a/web-marketplace/src/pages/Projects/AllProjects/AllProjects.tsx b/web-marketplace/src/pages/Projects/AllProjects/AllProjects.tsx index 19963e88df..db39879fef 100644 --- a/web-marketplace/src/pages/Projects/AllProjects/AllProjects.tsx +++ b/web-marketplace/src/pages/Projects/AllProjects/AllProjects.tsx @@ -1,5 +1,5 @@ -import React, { useEffect, useMemo, useState } from 'react'; -import { useLocation, useNavigate, useParams } from 'react-router-dom'; +import React, { useEffect, useMemo } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; import { Trans } from '@lingui/macro'; import { useLingui } from '@lingui/react'; import { Box, SelectChangeEvent, useMediaQuery, useTheme } from '@mui/material'; @@ -39,8 +39,8 @@ import { import { getAllSanityCreditClassesQuery } from 'lib/queries/react-query/sanity/getAllCreditClassesQuery/getAllCreditClassesQuery'; import { useTracker } from 'lib/tracker/useTracker'; -import { BuySellOrderFlow } from 'features/marketplace/BuySellOrderFlow/BuySellOrderFlow'; import { TebuBannerWrapper } from 'components/organisms/TebuBannerWrapper/TebuBannerWrapper'; +import { useOnBuyButtonClick } from 'hooks/useOnBuyButtonClick'; import { useFetchCreditClasses } from '../hooks/useFetchCreditClasses'; import { useProjectsContext } from '../Projects.context'; @@ -55,7 +55,6 @@ import { } from './AllProjects.constants'; import { normalizeCreditClassFilters } from './AllProjects.normalizers'; import { SideFilter } from './AllProjects.SideFilter'; -import { ProjectWithOrderData } from './AllProjects.types'; import { getCreditsTooltip } from './utils/getCreditsTooltip'; import { getIsSoldOut } from './utils/getIsSoldOut'; @@ -66,7 +65,6 @@ export const AllProjects: React.FC> = () => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const { track } = useTracker(); - const location = useLocation(); const config = getClientConfig(); const bodyTexts = useMemo(() => getProjectCardBodyTextMapping(_), [_]); @@ -96,8 +94,6 @@ export const AllProjects: React.FC> = () => { ); const [sort, setSort] = useAtom(projectsSortAtom); - const [selectedProject, setSelectedProject] = - useState(null); const { allProjects, @@ -107,6 +103,7 @@ export const AllProjects: React.FC> = () => { hasCommunityProjects, pagesCount, soldOutProjectsIds, + loading, } = useProjectsContext(); const { creditClassFilters } = normalizeCreditClassFilters({ @@ -150,7 +147,7 @@ export const AllProjects: React.FC> = () => { setCreditClassSelectedFilters, ]); - const [isBuyFlowStarted, setIsBuyFlowStarted] = useState(false); + const onBuyButtonClick = useOnBuyButtonClick(); const handleSort = (event: SelectChangeEvent): void => { setSort(event.target.value as string); @@ -242,8 +239,11 @@ export const AllProjects: React.FC> = () => { IS_TERRASOS ? undefined : () => { - setSelectedProject(project); - setIsBuyFlowStarted(true); + onBuyButtonClick({ + projectId: project?.id, + cardSellOrders: project?.cardSellOrders, + loading, + }); } } purchaseInfo={project.purchaseInfo || {}} @@ -305,15 +305,6 @@ export const AllProjects: React.FC> = () => { colorScheme={COLOR_SCHEME} /> - {config.buySellOrderFlow && ( - - )} ); }; diff --git a/web-marketplace/src/pages/Projects/Projects.context.tsx b/web-marketplace/src/pages/Projects/Projects.context.tsx index 3835c8123e..29713aa4c8 100644 --- a/web-marketplace/src/pages/Projects/Projects.context.tsx +++ b/web-marketplace/src/pages/Projects/Projects.context.tsx @@ -1,13 +1,14 @@ import { useOutletContext } from 'react-router-dom'; import { Maybe, PrefinanceProjects } from 'generated/sanity-graphql'; +import { NormalizeProject } from 'lib/normalizers/projects/normalizeProjectsWithMetadata'; import { ProjectWithOrderData } from './AllProjects/AllProjects.types'; type ProjectsContextType = { allProjects: ProjectWithOrderData[]; - prefinanceProjects: ProjectWithOrderData[]; - projects: ProjectWithOrderData[]; + prefinanceProjects: NormalizeProject[]; + projects: NormalizeProject[]; projectsCount?: number; loading: boolean; hasCommunityProjects: boolean; diff --git a/web-marketplace/src/pages/Projects/hooks/useProjectsSellOrders.types.ts b/web-marketplace/src/pages/Projects/hooks/useProjectsSellOrders.types.ts index 929751d661..e334e8b67d 100644 --- a/web-marketplace/src/pages/Projects/hooks/useProjectsSellOrders.types.ts +++ b/web-marketplace/src/pages/Projects/hooks/useProjectsSellOrders.types.ts @@ -1,9 +1,11 @@ +import { NormalizeProject } from 'lib/normalizers/projects/normalizeProjectsWithMetadata'; + import { ProjectWithOrderData } from '../AllProjects/AllProjects.types'; export interface ProjectsSellOrders { allProjects: ProjectWithOrderData[]; - prefinanceProjects: ProjectWithOrderData[]; - projectsWithOrderData: ProjectWithOrderData[]; + prefinanceProjects: NormalizeProject[]; + projectsWithOrderData: NormalizeProject[]; projectsCount?: number; loading: boolean; hasCommunityProjects: boolean;