diff --git a/app/grant/[id]/[slug]/layout.tsx b/app/grant/[id]/[slug]/layout.tsx index 9643aa24a..6e6d67e97 100644 --- a/app/grant/[id]/[slug]/layout.tsx +++ b/app/grant/[id]/[slug]/layout.tsx @@ -68,6 +68,7 @@ export default async function GrantSlugLayout({ params, children }: Props) { return ( - - {grant?.description && } - - + {grant?.description && } + ); } diff --git a/app/layouts/PageLayout.tsx b/app/layouts/PageLayout.tsx index 1fc1d1396..0b014e793 100644 --- a/app/layouts/PageLayout.tsx +++ b/app/layouts/PageLayout.tsx @@ -29,6 +29,7 @@ interface PageLayoutProps { className?: string; sidebarContentClassName?: string; topBanner?: ReactNode; + fundraiseGrantId?: number; /** * Drop the 860px main-content cap and let content fill the page container * (~1180px). Useful when `rightSidebar` is false and the page wants the @@ -129,10 +130,10 @@ function PageLayoutInner({ ); } -export function PageLayout(props: PageLayoutProps) { +export function PageLayout({ fundraiseGrantId, ...props }: PageLayoutProps) { return ( - + diff --git a/components/Funding/OpenFundingOpportunityModal.tsx b/components/Funding/OpenFundingOpportunityModal.tsx index 2697310a9..97d462633 100644 --- a/components/Funding/OpenFundingOpportunityModal.tsx +++ b/components/Funding/OpenFundingOpportunityModal.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, useState } from 'react'; +import { useEffect, useState, useTransition } from 'react'; import Link from 'next/link'; import { Dialog } from '@headlessui/react'; import { @@ -109,17 +109,36 @@ export const OpenFundingOpportunityModal = ({ }: OpenFundingOpportunityModalProps) => { const initialStep: Step = minimal ? 'method' : 'benefits'; const [step, setStep] = useState(initialStep); + const [pendingMethod, setPendingMethod] = useState(null); + const [isPending, startTransition] = useTransition(); + + const handleClose = () => { + if (isPending) return; + onClose(); + }; + + const handleConfirmMethod = (method: FundingOpportunityCreationMethod) => { + setPendingMethod(method); + startTransition(() => { + onConfirm(method); + }); + }; // Reset to the first step whenever the modal is reopened so a returning user // always starts from the configured entry step rather than a stale step. + // Skip while a route transition is pending so the method step doesn't flash + // back to the initial step before navigation completes. useEffect(() => { - if (!isOpen) setStep(initialStep); - }, [isOpen, initialStep]); + if (!isOpen && !isPending) { + setStep(initialStep); + setPendingMethod(null); + } + }, [isOpen, initialStep, isPending]); return ( @@ -172,7 +191,7 @@ export const OpenFundingOpportunityModal = ({