diff --git a/src/components/GenerateRoadmap/GenerateRoadmap.tsx b/src/components/GenerateRoadmap/GenerateRoadmap.tsx index 6d0414441..1c8050bea 100644 --- a/src/components/GenerateRoadmap/GenerateRoadmap.tsx +++ b/src/components/GenerateRoadmap/GenerateRoadmap.tsx @@ -35,8 +35,9 @@ import { readAIRoadmapStream, } from '../../lib/ai.ts'; import { AITermSuggestionInput } from './AITermSuggestionInput.tsx'; -import { IncreaseRoadmapLimit } from './IncreaseRoadmapLimit.tsx'; import { AuthenticationForm } from '../AuthenticationFlow/AuthenticationForm.tsx'; +import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal.tsx'; +import { useIsPaidUser } from '../../queries/billing.ts'; export type GetAIRoadmapLimitResponse = { used: number; @@ -101,6 +102,7 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) { const roadmapContainerRef = useRef<HTMLDivElement>(null); + const { isPaidUser, isLoading: isLoadingPaidUser } = useIsPaidUser(); const { rc: referralCode } = getUrlParams() as { rc?: string; }; @@ -472,12 +474,25 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) { } const pageUrl = `https://roadmap.sh/ai/${roadmapSlug}`; - const canGenerateMore = roadmapLimitUsed < roadmapLimit; + const canGenerateMore = roadmapLimitUsed < roadmapLimit || isPaidUser; + const isGenerateButtonDisabled = + isLoadingResults || + (isAuthenticatedUser && + // if no limit, + (!roadmapLimit || + // no roadmap term, + !roadmapTerm || + // if limit is reached and user is not paid user, + (roadmapLimitUsed >= roadmapLimit && !isPaidUser) || + // if roadmap term is the same as the current roadmap term, + roadmapTerm === currentRoadmap?.term || + // if key only, + isKeyOnly)); return ( <> {isConfiguring && ( - <IncreaseRoadmapLimit + <UpgradeAccountModal onClose={() => { setIsConfiguring(false); loadAIRoadmapLimit().finally(() => null); @@ -519,7 +534,7 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) { {!isLoading && ( <div className="container flex flex-grow flex-col items-start"> <AIRoadmapAlert /> - {isKeyOnly && isAuthenticatedUser && ( + {isKeyOnly && isAuthenticatedUser && !isPaidUser && ( <div className="flex flex-row gap-4"> <p className={'text-left text-red-500'}> We have hit the limit for AI roadmap generation. Please try @@ -533,7 +548,7 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) { </p> </div> )} - {!isKeyOnly && isAuthenticatedUser && ( + {!isKeyOnly && isAuthenticatedUser && !isPaidUser && ( <div className="mt-2 flex w-full flex-col items-start justify-between gap-2 text-sm sm:flex-row sm:items-center sm:gap-0"> <span> <span @@ -582,7 +597,7 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) { <button type={'submit'} className={cn( - 'flex min-w-[127px] flex-shrink-0 items-center justify-center gap-2 rounded-md bg-black px-4 py-2 text-white', + 'flex min-w-[127px] flex-shrink-0 items-center justify-center gap-2 rounded-md bg-black px-4 py-2.5 text-white', 'disabled:cursor-not-allowed disabled:opacity-50', )} onClick={(e) => { @@ -591,15 +606,7 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) { showLoginPopup(); } }} - disabled={ - isLoadingResults || - (isAuthenticatedUser && - (!roadmapLimit || - !roadmapTerm || - roadmapLimitUsed >= roadmapLimit || - roadmapTerm === currentRoadmap?.term || - isKeyOnly)) - } + disabled={isGenerateButtonDisabled} > {isLoadingResults && ( <> diff --git a/src/components/GenerateRoadmap/RoadmapSearch.tsx b/src/components/GenerateRoadmap/RoadmapSearch.tsx index cb26813c0..62cdab641 100644 --- a/src/components/GenerateRoadmap/RoadmapSearch.tsx +++ b/src/components/GenerateRoadmap/RoadmapSearch.tsx @@ -5,7 +5,8 @@ import { isLoggedIn } from '../../lib/jwt'; import { showLoginPopup } from '../../lib/popup'; import { cn } from '../../lib/classname.ts'; import { AITermSuggestionInput } from './AITermSuggestionInput.tsx'; -import { IncreaseRoadmapLimit } from './IncreaseRoadmapLimit.tsx'; +import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal.tsx'; +import { useIsPaidUser } from '../../queries/billing.ts'; type RoadmapSearchProps = { roadmapTerm: string; @@ -30,6 +31,7 @@ export function RoadmapSearch(props: RoadmapSearchProps) { isKeyOnly, } = props; + const { isPaidUser, isLoading } = useIsPaidUser(); const canGenerateMore = limitUsed < limit; const [isConfiguring, setIsConfiguring] = useState(false); const [isAuthenticatedUser, setIsAuthenticatedUser] = useState(false); @@ -44,7 +46,7 @@ export function RoadmapSearch(props: RoadmapSearchProps) { return ( <div className="flex flex-grow flex-col items-center px-4 py-6 sm:px-6 md:my-24 lg:my-32"> {isConfiguring && ( - <IncreaseRoadmapLimit + <UpgradeAccountModal onClose={() => { setIsConfiguring(false); loadAIRoadmapLimit(); @@ -193,7 +195,7 @@ export function RoadmapSearch(props: RoadmapSearchProps) { </p> </div> )} - {isKeyOnly && isAuthenticatedUser && ( + {isKeyOnly && isAuthenticatedUser && !isPaidUser && ( <div className="mx-auto mt-12 flex max-w-[450px] flex-col items-center gap-4"> <p className={'text-center text-red-500'}> We have hit the limit for AI roadmap generation. Please try again @@ -222,7 +224,7 @@ export function RoadmapSearch(props: RoadmapSearchProps) { </p> </div> )} - {!isKeyOnly && limit > 0 && isAuthenticatedUser && ( + {!isKeyOnly && limit > 0 && isAuthenticatedUser && !isPaidUser && ( <div className="mt-12 flex flex-col items-center gap-4"> <p className="text-center text-gray-500"> You have generated{' '} @@ -235,17 +237,15 @@ export function RoadmapSearch(props: RoadmapSearchProps) { </span>{' '} roadmaps today. </p> - {isAuthenticatedUser && ( - <p className="flex items-center text-sm"> - <button - onClick={() => setIsConfiguring(true)} - className="rounded-xl border border-current px-2 py-0.5 text-sm text-blue-500 transition-colors hover:bg-blue-400 hover:text-white" - > - Need to generate more?{' '} - <span className="font-semibold">Click here.</span> - </button> - </p> - )} + <p className="flex items-center text-sm"> + <button + onClick={() => setIsConfiguring(true)} + className="rounded-xl border border-current px-2 py-0.5 text-sm text-blue-500 transition-colors hover:bg-blue-400 hover:text-white" + > + Need to generate more?{' '} + <span className="font-semibold">Click here.</span> + </button> + </p> </div> )} </div> diff --git a/src/pages/ai/[aiRoadmapSlug].astro b/src/pages/ai/[aiRoadmapSlug].astro index 03243697f..79fbfbf97 100644 --- a/src/pages/ai/[aiRoadmapSlug].astro +++ b/src/pages/ai/[aiRoadmapSlug].astro @@ -2,6 +2,7 @@ import { aiRoadmapApi } from '../../api/ai-roadmap'; import BaseLayout from '../../layouts/BaseLayout.astro'; import { GenerateRoadmap } from '../../components/GenerateRoadmap/GenerateRoadmap'; +import { CheckSubscriptionVerification } from '../../components/Billing/CheckSubscriptionVerification'; export const prerender = false; @@ -31,4 +32,5 @@ const title = roadmap?.title || 'Roadmap AI'; isAuthenticatedUser={roadmap?.isAuthenticatedUser} client:load /> + <CheckSubscriptionVerification client:load /> </BaseLayout> diff --git a/src/pages/ai/index.astro b/src/pages/ai/index.astro index c2c7c1e6d..40a280b0d 100644 --- a/src/pages/ai/index.astro +++ b/src/pages/ai/index.astro @@ -1,8 +1,10 @@ --- import { GenerateRoadmap } from '../../components/GenerateRoadmap/GenerateRoadmap'; import BaseLayout from '../../layouts/BaseLayout.astro'; +import { CheckSubscriptionVerification } from '../../components/Billing/CheckSubscriptionVerification'; --- -<BaseLayout title='Roadmap AI' permalink="/ai"> +<BaseLayout title='Roadmap AI' permalink='/ai'> <GenerateRoadmap client:load /> + <CheckSubscriptionVerification client:load /> </BaseLayout>