diff --git a/src/components/AITutor/AIFeaturedCoursesListing.tsx b/src/components/AITutor/AIFeaturedCoursesListing.tsx
index 72520266f..8799ce06d 100644
--- a/src/components/AITutor/AIFeaturedCoursesListing.tsx
+++ b/src/components/AITutor/AIFeaturedCoursesListing.tsx
@@ -4,10 +4,13 @@ import {
} from '../../queries/ai-course';
import { queryClient } from '../../stores/query-client';
import { useEffect, useState } from 'react';
-import { Loader2 } from 'lucide-react';
import { getUrlParams, setUrlParams, deleteUrlParam } from '../../lib/browser';
import { AICourseCard } from '../GenerateCourse/AICourseCard';
import { Pagination } from '../Pagination/Pagination';
+import { AILoadingState } from './AILoadingState';
+import { AITutorTallMessage } from './AITutorTallMessage';
+import { BookOpen } from 'lucide-react';
+import { AITutorHeader } from './AITutorHeader';
type AIFeaturedCoursesListingProps = {};
@@ -47,34 +50,45 @@ export function AIFeaturedCoursesListing(props: AIFeaturedCoursesListingProps) {
}
}, [pageState]);
- return (
- <>
-
+ if (isInitialLoading || isFeaturedAiCoursesLoading) {
+ return (
+
+ );
+ }
- {(isFeaturedAiCoursesLoading || isInitialLoading) && (
-
- )}
+ if (courses.length === 0) {
+ return (
+ {
+ window.location.href = '/ai';
+ }}
+ />
+ );
+ }
+
+ return (
+
+
{!isFeaturedAiCoursesLoading && courses && courses.length > 0 && (
- {courses.map((course) => (
-
- ))}
+
+ {courses.map((course) => (
+
+ ))}
+
)}
- >
+
);
}
diff --git a/src/components/AITutor/AITutorHeader.tsx b/src/components/AITutor/AITutorHeader.tsx
new file mode 100644
index 000000000..07b447422
--- /dev/null
+++ b/src/components/AITutor/AITutorHeader.tsx
@@ -0,0 +1,46 @@
+import { useQuery } from '@tanstack/react-query';
+import { AITutorLimits } from './AITutorLimits';
+import { getAiCourseLimitOptions } from '../../queries/ai-course';
+import { queryClient } from '../../stores/query-client';
+
+type AITutorHeaderProps = {
+ title: string;
+ isPaidUser: boolean;
+ isPaidUserLoading: boolean;
+ setShowUpgradePopup: (show: boolean) => void;
+ children?: React.ReactNode;
+};
+
+export function AITutorHeader(props: AITutorHeaderProps) {
+ const {
+ title,
+ isPaidUser,
+ isPaidUserLoading,
+ setShowUpgradePopup,
+ children,
+ } = props;
+
+ const { data: limits } = useQuery(getAiCourseLimitOptions(), queryClient);
+
+ const { used, limit } = limits ?? { used: 0, limit: 0 };
+
+ return (
+
+
+
{title}
+
+
+
+
setShowUpgradePopup(true)}
+ />
+
+ {children}
+
+
+ );
+}
diff --git a/src/components/AITutor/AITutorLimits.tsx b/src/components/AITutor/AITutorLimits.tsx
new file mode 100644
index 000000000..3cc93730e
--- /dev/null
+++ b/src/components/AITutor/AITutorLimits.tsx
@@ -0,0 +1,45 @@
+import { Gift } from 'lucide-react';
+import { cn } from '../../lib/classname';
+
+type AITutorLimitsProps = {
+ used: number;
+ limit: number;
+ isPaidUser: boolean;
+ isPaidUserLoading: boolean;
+ onUpgradeClick: () => void;
+};
+
+export function AITutorLimits(props: AITutorLimitsProps) {
+ const limitUsedPercentage = Math.round((props.used / props.limit) * 100);
+
+ if (props.used <= 0 || props.limit <= 0 || props.isPaidUserLoading) {
+ return null;
+ }
+
+ return (
+
+
+
+ {limitUsedPercentage}% of daily limit used{' '}
+
+
+ {limitUsedPercentage}% used
+
+
+
+ Upgrade
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/GenerateCourse/UserCoursesList.tsx b/src/components/GenerateCourse/UserCoursesList.tsx
index ee56d665a..b39e061e9 100644
--- a/src/components/GenerateCourse/UserCoursesList.tsx
+++ b/src/components/GenerateCourse/UserCoursesList.tsx
@@ -1,23 +1,22 @@
import { useQuery } from '@tanstack/react-query';
+import { BookOpen } from 'lucide-react';
+import { useEffect, useState } from 'react';
+import { deleteUrlParam, getUrlParams, setUrlParams } from '../../lib/browser';
+import { isLoggedIn } from '../../lib/jwt';
+import { showLoginPopup } from '../../lib/popup';
import {
- getAiCourseLimitOptions,
listUserAiCoursesOptions,
type ListUserAiCoursesQuery,
} from '../../queries/ai-course';
-import { queryClient } from '../../stores/query-client';
-import { AICourseCard } from './AICourseCard';
-import { useEffect, useState } from 'react';
-import { BookOpen, Gift } from 'lucide-react';
-import { isLoggedIn } from '../../lib/jwt';
-import { showLoginPopup } from '../../lib/popup';
-import { cn } from '../../lib/classname';
import { useIsPaidUser } from '../../queries/billing';
-import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal';
-import { getUrlParams, setUrlParams, deleteUrlParam } from '../../lib/browser';
-import { AICourseSearch } from './AICourseSearch';
-import { Pagination } from '../Pagination/Pagination';
+import { queryClient } from '../../stores/query-client';
import { AILoadingState } from '../AITutor/AILoadingState';
+import { AITutorHeader } from '../AITutor/AITutorHeader';
import { AITutorTallMessage } from '../AITutor/AITutorTallMessage';
+import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal';
+import { Pagination } from '../Pagination/Pagination';
+import { AICourseCard } from './AICourseCard';
+import { AICourseSearch } from './AICourseSearch';
type UserCoursesListProps = {};
@@ -31,12 +30,6 @@ export function UserCoursesList(props: UserCoursesListProps) {
query: '',
});
- const { data: limits, isLoading: isLimitsLoading } = useQuery(
- getAiCourseLimitOptions(),
- queryClient,
- );
-
- const { used, limit } = limits ?? { used: 0, limit: 0 };
const { isPaidUser, isLoading: isPaidUserLoading } = useIsPaidUser();
const { data: userAiCourses, isFetching: isUserAiCoursesLoading } = useQuery(
@@ -49,8 +42,6 @@ export function UserCoursesList(props: UserCoursesListProps) {
}, [userAiCourses]);
const courses = userAiCourses?.data ?? [];
- const isAuthenticated = isLoggedIn();
- const limitUsedPercentage = Math.round((used / limit) * 100);
useEffect(() => {
const queryParams = getUrlParams();
@@ -116,55 +107,24 @@ export function UserCoursesList(props: UserCoursesListProps) {
{showUpgradePopup && (
setShowUpgradePopup(false)} />
)}
-
-
-
- Your Courses
-
-
-
- {used > 0 && limit > 0 && !isPaidUserLoading && (
-
-
-
- {limitUsedPercentage}% of daily limit used{' '}
-
-
- {limitUsedPercentage}% used
-
- {
- setShowUpgradePopup(true);
- }}
- className="ml-1.5 flex items-center gap-1 rounded-full bg-yellow-600 py-0.5 pr-2 pl-1.5 text-xs text-white"
- >
-
- Upgrade
-
-
-
- )}
-
-
{
- setPageState({
- ...pageState,
- query: value,
- currPage: '1',
- });
- }}
- />
-
-
+
+ {
+ setPageState({
+ ...pageState,
+ query: value,
+ currPage: '1',
+ });
+ }}
+ />
+
{!isUserAiCoursesLoading && courses && courses.length > 0 && (
diff --git a/src/pages/ai/staff-picks.astro b/src/pages/ai/staff-picks.astro
index 840680333..8fcae506a 100644
--- a/src/pages/ai/staff-picks.astro
+++ b/src/pages/ai/staff-picks.astro
@@ -12,10 +12,6 @@ const ogImage = 'https://roadmap.sh/og-images/ai-tutor.png';
description='Learn anything with AI Tutor. Pick a topic, choose a difficulty level and the AI will guide you through the learning process.'
>
-
+