From e9330a2e632fda15f67fbad244edde72e24f4003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20=C3=85strand?= Date: Tue, 27 Jan 2026 12:55:13 +1100 Subject: [PATCH 1/3] fix: APP-877 add project pages to react router --- web-marketplace/src/clients/regen/Regen.Routes.tsx | 6 ++++++ .../components/templates/ProjectDetails/ProjectDetails.tsx | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/web-marketplace/src/clients/regen/Regen.Routes.tsx b/web-marketplace/src/clients/regen/Regen.Routes.tsx index 6978f3bc32..25ee109b0e 100644 --- a/web-marketplace/src/clients/regen/Regen.Routes.tsx +++ b/web-marketplace/src/clients/regen/Regen.Routes.tsx @@ -70,6 +70,11 @@ const BasketDetails = safeLazy( ); const BuyCredits = safeLazy(() => import('../../legacy-pages/BuyCredits')); const Sell = safeLazy(() => import('../../legacy-pages/Sell/Sell')); +const ProjectDetails = safeLazy(() => + import('../../components/templates/ProjectDetails/ProjectDetails').then( + mod => ({ default: mod.ProjectDetails }), + ), +); const ChooseCreditClassPage = safeLazy( () => import('../../legacy-pages/ChooseCreditClass'), @@ -300,6 +305,7 @@ export const getRegenRoutes = ({ /> } /> + } /> } /> (); + const { projectId } = useParams<{ projectId: string }>(); const { queryClient } = useLedger(); const { isConnected, isKeplrMobileWeb, wallet, loginDisabled } = useWallet(); const graphqlClient = From 4ad29bb61b31eba151f035d062d102dd5bdaa2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20=C3=85strand?= Date: Tue, 27 Jan 2026 13:21:10 +1100 Subject: [PATCH 2/3] fix: APP-877 remove next js project page, fix dashboard flashing on certain paths --- .../src/app/[lang]/project/[id]/page.tsx | 165 ------------------ .../src/legacy-pages/Dashboard/Dashboard.tsx | 12 ++ 2 files changed, 12 insertions(+), 165 deletions(-) delete mode 100644 web-marketplace/src/app/[lang]/project/[id]/page.tsx diff --git a/web-marketplace/src/app/[lang]/project/[id]/page.tsx b/web-marketplace/src/app/[lang]/project/[id]/page.tsx deleted file mode 100644 index 70cf943200..0000000000 --- a/web-marketplace/src/app/[lang]/project/[id]/page.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import { cache } from 'react'; -import { - dehydrate, - HydrationBoundary, - QueryClient, -} from '@tanstack/react-query'; -import { getClient, getSanityClient } from 'app/ApolloClient'; -import { getRPCQueryClient } from 'app/makeRPCQueryClient'; -import { redirect } from 'next/navigation'; - -import { Maybe, ProjectFieldsFragment } from 'generated/graphql'; -import { getProjectQuery } from 'lib/queries/react-query/ecocredit/getProjectQuery/getProjectQuery'; -import { getSellOrdersExtendedQuery } from 'lib/queries/react-query/ecocredit/marketplace/getSellOrdersExtendedQuery/getSellOrdersExtendedQuery'; -import { getMetadataQuery } from 'lib/queries/react-query/registry-server/getMetadataQuery/getMetadataQuery'; -import { getProjectByIdQuery as getOffChainProjectByIdQuery } from 'lib/queries/react-query/registry-server/graphql/getProjectByIdQuery/getProjectByIdQuery'; -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 { getAllProjectPageQuery } from 'lib/queries/react-query/sanity/getAllProjectPageQuery/getAllProjectPageQuery'; - -import { ProjectDetails } from 'components/templates/ProjectDetails'; -import { - getIsOnChainId, - getIsUuid, -} from 'components/templates/ProjectDetails/ProjectDetails.utils'; - -interface ProjectPageProps { - params: Promise<{ id: string; lang: string }>; -} - -const getProject = cache(async (id: string, lang: string) => { - try { - const isOnChainId = getIsOnChainId(id); - const isOffChainUuid = getIsUuid(id); - let onChainProjectId: Maybe | undefined; - let offChainProject: Maybe | undefined; - let slug: Maybe | undefined; - - const queryClient = new QueryClient(); - const apolloClient = await getClient(); - const rpcQueryClient = await getRPCQueryClient(); - if (isOnChainId) { - const offChainProjectByIdData = await queryClient.fetchQuery( - getProjectByOnChainIdQuery({ - client: apolloClient, - onChainId: id, - languageCode: lang, - }), - ); - onChainProjectId = id; - offChainProject = offChainProjectByIdData?.data?.projectByOnChainId; - slug = offChainProject?.slug; - } else if (isOffChainUuid) { - const offChainProjectByIdData = await queryClient.fetchQuery( - getOffChainProjectByIdQuery({ - client: apolloClient, - id, - languageCode: lang, - }), - ); - offChainProject = offChainProjectByIdData?.data?.projectById; - onChainProjectId = offChainProject?.onChainId; - slug = offChainProject?.slug; - } else { - const projectBySlug = await queryClient.fetchQuery( - getProjectBySlugQuery({ - client: apolloClient, - slug: id, - languageCode: lang, - }), - ); - offChainProject = projectBySlug?.data.projectBySlug; - onChainProjectId = offChainProject?.onChainId; - } - - const projectResponse = await queryClient.fetchQuery( - getProjectQuery({ - request: { projectId: onChainProjectId as string }, - client: rpcQueryClient, - enabled: !!rpcQueryClient && !!onChainProjectId, - }), - ); - const onChainProject = projectResponse?.project; - - const metadataResponse = await queryClient.fetchQuery( - getMetadataQuery({ - iri: onChainProject?.metadata, - client: rpcQueryClient, - enabled: !!rpcQueryClient, - languageCode: lang, - }), - ); - - return { - projectMetadata: metadataResponse, - projectPageMetadata: offChainProject?.metadata, - slug, - rpcQueryClient, - queryClient, - }; - } catch (error) { - throw error; - } -}); - -export async function generateMetadata({ params }: ProjectPageProps) { - const { id, lang } = await params; - - const { projectMetadata, projectPageMetadata } = await getProject(id, lang); - const title = - projectMetadata?.['schema:name'] || projectPageMetadata?.['schema:name']; - const description = projectPageMetadata?.['schema:description']; - const image = - projectPageMetadata?.['schema:image'] || - projectPageMetadata?.['regen:previewPhoto']?.['schema:url']; - - return { - title, - description, - openGraph: { - title, - description, - images: image ? [new URL(image)] : undefined, - }, - }; -} - -export default async function ProjectPage({ params }: ProjectPageProps) { - const { id, lang } = await params; - - const sanityClient = await getSanityClient(); - const { rpcQueryClient, queryClient, slug } = await getProject(id, lang); - if (slug) { - redirect(`/${lang}/project/${slug}`); - } - - queryClient.prefetchQuery( - getAllProjectPageQuery({ - sanityClient: sanityClient, - languageCode: lang, - }), - ); - - queryClient.prefetchQuery( - getAllSanityCreditClassesQuery({ - sanityClient: sanityClient, - languageCode: lang, - }), - ); - - if (rpcQueryClient) - queryClient.prefetchQuery( - getSellOrdersExtendedQuery({ - client: rpcQueryClient, - reactQueryClient: queryClient, - request: {}, - }), - ); - - return ( - - - - ); -} diff --git a/web-marketplace/src/legacy-pages/Dashboard/Dashboard.tsx b/web-marketplace/src/legacy-pages/Dashboard/Dashboard.tsx index 9e1c9dca1d..963fcab197 100644 --- a/web-marketplace/src/legacy-pages/Dashboard/Dashboard.tsx +++ b/web-marketplace/src/legacy-pages/Dashboard/Dashboard.tsx @@ -78,6 +78,13 @@ import { useBridgeAvailability } from './hooks/useBridgeAvailabilty'; import { usePathSection } from './hooks/usePathSection'; import { useFetchProjectByAdmin } from './MyProjects/hooks/useFetchProjectsByAdmin'; +// Preload lazy-loaded dashboard sub-pages to prevent flash on first navigation +const preloadDashboardPages = () => { + import('../Orders'); + import('./Members'); + import('../Sell/Sell'); +}; + export const Dashboard = () => { const { _ } = useLingui(); const [selectedLanguage] = useAtom(selectedLanguageAtom); @@ -85,6 +92,11 @@ export const Dashboard = () => { const { loading, activeAccount, activeAccountId, privActiveAccount } = useAuth(); + // Preload dashboard sub-pages on mount to eliminate navigation flash + useEffect(() => { + preloadDashboardPages(); + }, []); + const [isWarningModalOpen, setIsWarningModalOpen] = useState< string | undefined >(undefined); From d36f3c5f33a04c5ab3fda83fade379953e8516be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20=C3=85strand?= Date: Tue, 27 Jan 2026 13:37:16 +1100 Subject: [PATCH 3/3] fix: APP-877 add Suspense boundary around outlet to fix blinking navigation in dashboard --- web-marketplace/src/legacy-pages/Dashboard/Dashboard.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web-marketplace/src/legacy-pages/Dashboard/Dashboard.tsx b/web-marketplace/src/legacy-pages/Dashboard/Dashboard.tsx index 963fcab197..7914b69efe 100644 --- a/web-marketplace/src/legacy-pages/Dashboard/Dashboard.tsx +++ b/web-marketplace/src/legacy-pages/Dashboard/Dashboard.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { Suspense, useEffect, useMemo, useRef, useState } from 'react'; import { Outlet, useLocation, useNavigate } from 'react-router-dom'; import { ApolloClient, @@ -643,7 +643,9 @@ export const Dashboard = () => { 'lg:mt-30 min-h-[520px]', )} > - + + +