|
|
|
@ -17,9 +17,11 @@ import { |
|
|
|
|
} from 'react'; |
|
|
|
|
import type { AICourseViewMode } from './AICourseContent'; |
|
|
|
|
import { replaceChildren } from '../../lib/dom'; |
|
|
|
|
import { Loader2Icon } from 'lucide-react'; |
|
|
|
|
import { ErrorIcon } from '../ReactIcons/ErrorIcon'; |
|
|
|
|
import { Frown, Loader2Icon } from 'lucide-react'; |
|
|
|
|
import { renderTopicProgress } from '../../lib/resource-progress'; |
|
|
|
|
import { queryClient } from '../../stores/query-client'; |
|
|
|
|
import { useQuery } from '@tanstack/react-query'; |
|
|
|
|
import { billingDetailsOptions } from '../../queries/billing'; |
|
|
|
|
|
|
|
|
|
export type AICourseRoadmapViewProps = { |
|
|
|
|
done: string[]; |
|
|
|
@ -27,6 +29,7 @@ export type AICourseRoadmapViewProps = { |
|
|
|
|
setActiveModuleIndex: (index: number) => void; |
|
|
|
|
setActiveLessonIndex: (index: number) => void; |
|
|
|
|
setViewMode: (mode: AICourseViewMode) => void; |
|
|
|
|
onUpgradeClick: () => void; |
|
|
|
|
setExpandedModules: Dispatch<SetStateAction<Record<number, boolean>>>; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -38,6 +41,7 @@ export function AICourseRoadmapView(props: AICourseRoadmapViewProps) { |
|
|
|
|
setActiveLessonIndex, |
|
|
|
|
setViewMode, |
|
|
|
|
setExpandedModules, |
|
|
|
|
onUpgradeClick, |
|
|
|
|
} = props; |
|
|
|
|
|
|
|
|
|
const containerEl = useRef<HTMLDivElement>(null); |
|
|
|
@ -47,6 +51,11 @@ export function AICourseRoadmapView(props: AICourseRoadmapViewProps) { |
|
|
|
|
const [isGenerating, setIsGenerating] = useState(false); |
|
|
|
|
const [error, setError] = useState<string | null>(null); |
|
|
|
|
|
|
|
|
|
const { data: userBillingDetails, isLoading: isBillingDetailsLoading } = |
|
|
|
|
useQuery(billingDetailsOptions(), queryClient); |
|
|
|
|
|
|
|
|
|
const isPaidUser = userBillingDetails?.status === 'active'; |
|
|
|
|
|
|
|
|
|
const generateAICourseRoadmap = async (courseSlug: string) => { |
|
|
|
|
try { |
|
|
|
|
const response = await fetch( |
|
|
|
@ -179,7 +188,7 @@ export function AICourseRoadmapView(props: AICourseRoadmapViewProps) { |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<div className="relative mx-auto min-h-[200px] rounded-xl border border-gray-200 bg-white shadow-sm lg:max-w-7xl"> |
|
|
|
|
<div className="relative mx-auto min-h-[500px] rounded-xl border border-gray-200 bg-white shadow-sm lg:max-w-7xl"> |
|
|
|
|
{isLoading && ( |
|
|
|
|
<div className="absolute inset-0 flex h-full w-full items-center justify-center"> |
|
|
|
|
<Loader2Icon className="h-10 w-10 animate-spin stroke-[3px]" /> |
|
|
|
@ -188,10 +197,19 @@ export function AICourseRoadmapView(props: AICourseRoadmapViewProps) { |
|
|
|
|
|
|
|
|
|
{error && !isLoading && !isGenerating && ( |
|
|
|
|
<div className="absolute inset-0 flex h-full w-full flex-col items-center justify-center"> |
|
|
|
|
<ErrorIcon additionalClasses="h-10 w-10" /> |
|
|
|
|
<p className="mx-auto mt-4 max-w-sm text-balance text-center text-sm text-gray-500"> |
|
|
|
|
<Frown className="size-20 text-red-500" /> |
|
|
|
|
<p className="mx-auto mt-5 max-w-[250px] text-balance text-center text-base text-red-500"> |
|
|
|
|
{error || 'Something went wrong'} |
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
{!isPaidUser && (error || '')?.includes('limit') && ( |
|
|
|
|
<button |
|
|
|
|
onClick={onUpgradeClick} |
|
|
|
|
className="mt-5 rounded-full bg-red-600 px-4 py-1 text-white hover:bg-red-700" |
|
|
|
|
> |
|
|
|
|
Upgrade Account |
|
|
|
|
</button> |
|
|
|
|
)} |
|
|
|
|
</div> |
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|