Is paid user checks

refactor/ai-courses
Kamran Ahmed 1 month ago
parent 143e27bbdd
commit 0ac14cbbe8
  1. 17
      src/components/GenerateCourse/AICourseContent.tsx
  2. 79
      src/components/GenerateCourse/AICourseModuleView.tsx

@ -21,6 +21,7 @@ import { AICourseModuleView } from './AICourseModuleView';
import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal'; import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal';
import { AILimitsPopup } from './AILimitsPopup'; import { AILimitsPopup } from './AILimitsPopup';
import { RegenerateOutline } from './RegenerateOutline'; import { RegenerateOutline } from './RegenerateOutline';
import { useIsPaidUser } from '../../queries/billing';
type AICourseContentProps = { type AICourseContentProps = {
courseSlug?: string; courseSlug?: string;
@ -41,6 +42,8 @@ export function AICourseContent(props: AICourseContentProps) {
const [sidebarOpen, setSidebarOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false);
const [viewMode, setViewMode] = useState<'module' | 'full'>('full'); const [viewMode, setViewMode] = useState<'module' | 'full'>('full');
const { isPaidUser } = useIsPaidUser();
const { data: aiCourseProgress } = useQuery( const { data: aiCourseProgress } = useQuery(
getAiCourseProgressOptions({ aiCourseSlug: courseSlug || '' }), getAiCourseProgressOptions({ aiCourseSlug: courseSlug || '' }),
queryClient, queryClient,
@ -162,12 +165,14 @@ export function AICourseContent(props: AICourseContentProps) {
{isLimitReached && ( {isLimitReached && (
<div className="mt-4"> <div className="mt-4">
<button {!isPaidUser && (
onClick={() => setShowUpgradeModal(true)} <button
className="rounded-md bg-yellow-400 px-6 py-2 text-sm font-medium text-black hover:bg-yellow-500" onClick={() => setShowUpgradeModal(true)}
> className="rounded-md bg-yellow-400 px-6 py-2 text-sm font-medium text-black hover:bg-yellow-500"
Upgrade to remove Limits >
</button> Upgrade to remove Limits
</button>
)}
<p className="mt-4 text-sm text-black"> <p className="mt-4 text-sm text-black">
<a href="/ai-tutor" className="underline underline-offset-2"> <a href="/ai-tutor" className="underline underline-offset-2">

@ -25,6 +25,7 @@ import {
import { queryClient } from '../../stores/query-client'; import { queryClient } from '../../stores/query-client';
import { AICourseFollowUp } from './AICourseFollowUp'; import { AICourseFollowUp } from './AICourseFollowUp';
import './AICourseFollowUp.css'; import './AICourseFollowUp.css';
import { useIsPaidUser } from '../../queries/billing';
type AICourseModuleViewProps = { type AICourseModuleViewProps = {
courseSlug: string; courseSlug: string;
@ -72,6 +73,8 @@ export function AICourseModuleView(props: AICourseModuleViewProps) {
const lessonId = `${slugify(currentModuleTitle)}__${slugify(currentLessonTitle)}`; const lessonId = `${slugify(currentModuleTitle)}__${slugify(currentLessonTitle)}`;
const isLessonDone = aiCourseProgress?.done.includes(lessonId); const isLessonDone = aiCourseProgress?.done.includes(lessonId);
const { isPaidUser } = useIsPaidUser();
const abortController = useMemo( const abortController = useMemo(
() => new AbortController(), () => new AbortController(),
[activeModuleIndex, activeLessonIndex], [activeModuleIndex, activeLessonIndex],
@ -124,36 +127,41 @@ export function AICourseModuleView(props: AICourseModuleViewProps) {
removeAuthToken(); removeAuthToken();
window.location.reload(); window.location.reload();
} }
return;
} }
const reader = response.body?.getReader(); if (!response.body) {
if (!reader) {
setIsLoading(false); setIsLoading(false);
setError('Something went wrong'); setError('No response body received');
return; return;
} }
setIsLoading(false); try {
setIsGenerating(true); const reader = response.body.getReader();
await readStream(reader, { setIsLoading(false);
onStream: async (result) => { setIsGenerating(true);
if (abortController.signal.aborted) { await readStream(reader, {
return; onStream: async (result) => {
} if (abortController.signal.aborted) {
return;
setLessonHtml(markdownToHtml(result, false)); }
},
onStreamEnd: async (result) => { setLessonHtml(markdownToHtml(result, false));
if (abortController.signal.aborted) { },
return; onStreamEnd: async (result) => {
} if (abortController.signal.aborted) {
return;
setLessonHtml(await markdownToHtmlWithHighlighting(result)); }
queryClient.invalidateQueries(getAiCourseLimitOptions());
setIsGenerating(false); setLessonHtml(await markdownToHtmlWithHighlighting(result));
}, queryClient.invalidateQueries(getAiCourseLimitOptions());
}); setIsGenerating(false);
},
});
} catch (e) {
setError(e instanceof Error ? e.message : 'Something went wrong');
setIsLoading(false);
}
}; };
const { mutate: toggleDone, isPending: isTogglingDone } = useMutation( const { mutate: toggleDone, isPending: isTogglingDone } = useMutation(
@ -273,18 +281,21 @@ export function AICourseModuleView(props: AICourseModuleViewProps) {
Limit reached Limit reached
</h2> </h2>
<p className="my-3 text-red-600"> <p className="my-3 text-red-600">
You have reached the AI usage limit for today. Please upgrade You have reached the AI usage limit for today.
your account to continue. {!isPaidUser && <>Please upgrade your account to continue.</>}
{isPaidUser && <>Please wait until tomorrow to continue.</>}
</p> </p>
<button {!isPaidUser && (
onClick={() => { <button
onUpgrade(); onClick={() => {
}} onUpgrade();
className="rounded-full bg-red-600 px-4 py-1 text-white hover:bg-red-700" }}
> className="rounded-full bg-red-600 px-4 py-1 text-white hover:bg-red-700"
Upgrade Account >
</button> Upgrade Account
</button>
)}
</div> </div>
) : ( ) : (
<p className="text-red-600">{error}</p> <p className="text-red-600">{error}</p>

Loading…
Cancel
Save