feat/ai-courses
Arik Chakma 2 months ago
parent 7854597935
commit cb5632160d
  1. 8
      src/components/Billing/UpgradeAccountModal.tsx
  2. 139
      src/components/GenerateCourse/AICourseLimit.tsx
  3. 23
      src/components/GenerateCourse/GetAICourse.tsx

@ -24,9 +24,13 @@ type CreateSubscriptionCheckoutSessionResponse = {
checkoutUrl: string; checkoutUrl: string;
}; };
type UpgradeAccountModalProps = {}; type UpgradeAccountModalProps = {
onClose: () => void;
};
export function UpgradeAccountModal(props: UpgradeAccountModalProps) { export function UpgradeAccountModal(props: UpgradeAccountModalProps) {
const { onClose } = props;
const [selectedPlan, setSelectedPlan] = const [selectedPlan, setSelectedPlan] =
useState<AllowedSubscriptionInterval>('month'); useState<AllowedSubscriptionInterval>('month');
const [isUpdatingPlan, setIsUpdatingPlan] = useState(false); const [isUpdatingPlan, setIsUpdatingPlan] = useState(false);
@ -115,7 +119,7 @@ export function UpgradeAccountModal(props: UpgradeAccountModalProps) {
return ( return (
<Modal <Modal
onClose={() => {}} onClose={onClose}
wrapperClassName="rounded-xl max-w-3xl w-full min-h-[540px]" wrapperClassName="rounded-xl max-w-3xl w-full min-h-[540px]"
bodyClassName="p-6" bodyClassName="p-6"
> >

@ -11,10 +11,12 @@ import { useState, useRef } from 'react';
import { getAiCourseLimitOptions } from '../../queries/ai-course'; import { getAiCourseLimitOptions } from '../../queries/ai-course';
import { queryClient } from '../../stores/query-client'; import { queryClient } from '../../stores/query-client';
import { useOutsideClick } from '../../hooks/use-outside-click'; import { useOutsideClick } from '../../hooks/use-outside-click';
import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal';
export function AICourseLimit() { export function AICourseLimit() {
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
const { data: limits, isLoading } = useQuery( const { data: limits, isLoading } = useQuery(
getAiCourseLimitOptions(), getAiCourseLimitOptions(),
@ -45,80 +47,93 @@ export function AICourseLimit() {
const followUpPercentage = Math.round((followUpUsed / followUpLimit) * 100); const followUpPercentage = Math.round((followUpUsed / followUpLimit) * 100);
return ( return (
<div className="relative z-10" ref={containerRef}> <>
<button <div className="relative z-10" ref={containerRef}>
className="flex h-full cursor-pointer items-center rounded-lg border border-gray-200 px-2 py-1.5 text-sm hover:bg-gray-50" <button
onClick={() => setIsOpen(!isOpen)} className="flex h-full cursor-pointer items-center rounded-lg border border-gray-200 px-2 py-1.5 text-sm hover:bg-gray-50"
> onClick={() => setIsOpen(!isOpen)}
<div className="mr-3 flex items-center gap-1.5"> >
<BookIcon className="h-4 w-4" /> <div className="mr-3 flex items-center gap-1.5">
{coursePercentage}% <BookIcon className="h-4 w-4" />
</div> {coursePercentage}%
<div className="mr-3 flex items-center gap-1.5"> </div>
<BookOpenIcon className="h-4 w-4" /> <div className="mr-3 flex items-center gap-1.5">
{lessonPercentage}% <BookOpenIcon className="h-4 w-4" />
</div> {lessonPercentage}%
<div className="mr-3 flex items-center gap-1.5"> </div>
<BotIcon className="h-4 w-4" /> <div className="mr-3 flex items-center gap-1.5">
{followUpPercentage}% <BotIcon className="h-4 w-4" />
</div> {followUpPercentage}%
</div>
<span className="mr-1">of daily limits</span>
<ChevronDownIcon className="h-4 w-4" /> <span className="mr-1">of daily limits</span>
</button> <ChevronDownIcon className="h-4 w-4" />
</button>
{isOpen && (
<div className="absolute right-0 top-full w-full translate-y-1 overflow-hidden rounded-lg border border-gray-200 bg-white p-2 pt-0 text-sm shadow-lg">
<div className="-mx-2">
<div className="relative overflow-hidden">
<div className="relative z-10 flex items-center gap-2 border-b border-b-gray-200 px-2 py-1">
<BookIcon className="size-3.5" />
{courseUsed} of {courseLimit} courses used
</div>
{isOpen && ( <div
<div className="absolute right-0 top-full w-full translate-y-1 overflow-hidden rounded-lg border border-gray-200 bg-white p-2 pt-0 text-sm shadow-lg"> className="absolute inset-0 bg-gray-100"
<div className="-mx-2"> style={{
<div className="relative overflow-hidden"> width: `${coursePercentage}%`,
<div className="relative z-10 flex items-center gap-2 border-b border-b-gray-200 px-2 py-1"> }}
<BookIcon className="size-3.5" /> />
{courseUsed} of {courseLimit} courses used
</div> </div>
<div <div className="relative overflow-hidden">
className="absolute inset-0 bg-gray-100" <div className="relative z-10 flex items-center gap-2 border-b border-b-gray-200 px-2 py-1">
style={{ <BookOpenIcon className="size-3.5" />
width: `${coursePercentage}%`, {lessonUsed} of {lessonLimit} lessons used
}} </div>
/>
</div>
<div className="relative overflow-hidden"> <div
<div className="relative z-10 flex items-center gap-2 border-b border-b-gray-200 px-2 py-1"> className="absolute inset-0 bg-gray-100"
<BookOpenIcon className="size-3.5" /> style={{
{lessonUsed} of {lessonLimit} lessons used width: `${lessonPercentage}%`,
}}
/>
</div> </div>
<div <div className="relative overflow-hidden">
className="absolute inset-0 bg-gray-100" <div className="relative z-10 flex items-center gap-2 border-b border-b-gray-200 px-2 py-1">
style={{ <BotIcon className="size-3.5" />
width: `${lessonPercentage}%`, {followUpUsed} of {followUpLimit} follow-ups used
}} </div>
/>
</div>
<div className="relative overflow-hidden"> <div
<div className="relative z-10 flex items-center gap-2 border-b border-b-gray-200 px-2 py-1"> className="absolute inset-0 bg-gray-100"
<BotIcon className="size-3.5" /> style={{
{followUpUsed} of {followUpLimit} follow-ups used width: `${followUpPercentage}%`,
}}
/>
</div> </div>
</div>
<div <div className="mt-2 flex items-center justify-center gap-2 text-gray-500">
className="absolute inset-0 bg-gray-100" <ClockIcon className="size-3.5" />
style={{ Limit resets every 24 hours
width: `${followUpPercentage}%`,
}}
/>
</div> </div>
</div> </div>
)}
</div>
<div className="mt-2 flex items-center justify-center gap-2 text-gray-500"> <button
<ClockIcon className="size-3.5" /> className="ml-2 rounded-md border border-gray-200 px-2 py-1 text-sm hover:bg-gray-50"
Limit resets every 24 hours onClick={() => setShowUpgradeModal(true)}
</div> >
</div> Upgrade
</button>
{showUpgradeModal && (
<UpgradeAccountModal onClose={() => setShowUpgradeModal(false)} />
)} )}
</div> </>
); );
} }

@ -45,18 +45,15 @@ export function GetAICourse(props: GetAICourseProps) {
}, [error]); }, [error]);
return ( return (
<> <AICourseContent
<UpgradeAccountModal /> course={{
<AICourseContent title: aiCourse?.title || '',
course={{ modules: aiCourse?.course.modules || [],
title: aiCourse?.title || '', difficulty: aiCourse?.difficulty || 'Easy',
modules: aiCourse?.course.modules || [], }}
difficulty: aiCourse?.difficulty || 'Easy', isLoading={isLoading}
}} courseSlug={courseSlug}
isLoading={isLoading} error={error?.message}
courseSlug={courseSlug} />
error={error?.message}
/>
</>
); );
} }

Loading…
Cancel
Save